# Verilog 3: RT Level Sequential
### 1. Synchronous Design
A sequential circuit is a circuit with memory, which forms the internal state of the circuit. Unlike a combinational circuit, in which the output is a function of input only, the output of a sequential circuit is a function of the input and the internal state.
The synchronous design methodology is the most commonly used practice in designing a sequential circuit. In this methodology, all storage elements are controlled (i.e., synchronized) by a global clock signal and the data is sampled and stored at the rising or falling edge of the clock signal.
### 2. D Flip-Flop and Register
The most basic storage component in a sequential circuit is a D-type flip-flop (D FF) as shown in the following figure.

This is the truth table for D FF. The next q value (q*) is equal to input d at the rising edge of the clock and when the reset is 1. Note that this rst_n signal is active-low, so the D FF is reset to 0 when the rst_n is 0.

This is the implementation of D FF in Verilog. In a sequential circuit, we use non-blocking assignments (<=) inside the always block.
```verilog
module dff
(
input wire clk,
input wire rst_n,
input wire d,
output reg q
);
always @(posedge clk)
if (!rst_n)
q <= 0;
else
q <= d;
endmodule
```
A register is a collection of D FFs that are controlled by the same clock and reset signals. The Verilog code of the register is the same as D FF, but it has more than 1 bit of input and output. This example shows an 8-bit register.
```verilog
module reg_8bit
(
input wire clk,
input wire rst_n,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk)
if (!rst_n)
q <= 0;
else
q <= d;
endmodule
```
### 3. Synchronous System
The following figure shows a block diagram of a synchronous system. It consists of the following parts:
- **State register**: a collection of D FFs controlled by the same clock signal (state_reg).
- **Next-state logic**: combinational logic that uses the external input and internal state (i.e., the output of register) to determine the new value of the register (state_next).
- **Output logic**: combinational logic that generates the output signal.

Synchronous system are classified into three groups based on their next-state logic properties:
- **Regular sequential circuit**: the state transitions in the circuit exhibit a "regular" pattern, as in a counter or shift register. The next-state logic is constructed primarily by a predesigned, "regular" component, such as an incrementor or shifter.
- **Finite state machine (FSM)**: the state transitions in the circuit do not exhibit a simple, repetitive pattern. The next-state logic is constructed by "random logic" and synthesized from scratch. It should be called a random sequential circuit, but is commonly known as an FSM (finite state machine).
- **Finite state machine with data path (FSMD)**: the circuit consists of a regular sequential circuit and an FSM. The two parts are known as a data path and a control path, and the complete circuit is known as an FSMD (FSM with data path).
### 4. Timing
There are four main timing parameters of a D FF: $T_{setup}$ (**Setup Time**), $T_{hold}$ (**Hold Time**), $T_{cq}$ (**Register Propagation Delay**), and $T_{comb}$ (**Combinational Propagation Delay**).
- $T_{setup}$ is the time before the active clock edge, when the data signal is not allowed to change its value.
- $T_{hold}$ is the time after the active clock edge, when the data signal is not allowed to change its value.
- $T_{cq}$ is the time required to propagate the value of d to q at the rising edge of the clock signal.

- $T_{comb}$ is the time required to propagate the input to output of combinational logic.

Each combinational logic has its propagation delay. Connecting long combinational logic causes path with longest propagation delay often called **critical path**. This path will limit maximum clock that we can achieve.

The timing of a sequential circuit is characterized by the maximal clock frequency, $f_{max}$. The reciprocal of $f_{max}$ specifies $T_{clock}$, the minimal clock period, which can be interpreted as the interval between two sampling edges of the clock. The minimal clock period can be obtained by adding the propagation delays and setup time constraint:
$$T_{clock}\geq T_{cq}+T_{comb}+T_{setup}$$
and the maximal clock rate is the reciprocal:
$$f_{max}=\frac{1}{T_{clock}}=\frac{1}{T_{cq}+T_{comb}+T_{setup}}$$
### 5. Design Examples
#### 5.1 Register
The following figure shows a register block diagram. It consists of a state register and next-state logic. This register has an active-low reset (rst_n) and a clear signal (clr). When either one of these signals is active, the register value will be set to 0. The enable signal controls the input either from the previous register value (q) or the new input (d). The value of the register will be updated only if the enable signal is 1.

This is the implementation of a register in Verilog. We use parameterized code to specify the register width.
```verilog=
module register
#(
parameter WIDTH = 16
)
(
input wire clk,
input wire rst_n,
input wire en,
input wire clr,
input wire signed [WIDTH-1:0] d,
output reg signed [WIDTH-1:0] q
);
always @(posedge clk)
begin
if (!rst_n || clr)
begin
q <= 0;
end
else if (en)
begin
q <= d;
end
end
endmodule
```
The following code is the testbench for the register.
```verilog=
`timescale 1ns / 1ps
module register_tb();
localparam T = 10;
reg clk, rst_n, en, clr;
reg [7:0] d;
wire [7:0] q;
register #(8)
dut(.clk(clk), .rst_n(rst_n), .en(en), .clr(clr), .d(d), .q(q));
always
begin
clk = 0;
#(T/2);
clk = 1;
#(T/2);
end
initial
begin
en = 1; clr = 0; d = 0;
rst_n = 0; #T;
rst_n = 1; #T;
d = 8'd8; #T;
d = 8'd16; #T;
clr = 1; #T;
end
endmodule
```
#### 5.2. Counter
The following figure shows a counter block diagram. It consists of a state register and next-state logic. This counter starts counting up when the start signal is 1. Then, it will count up from 0 to 5. After that, it resets back to 0 and waits for the start signal again.

This is the implementation of the counter in Verilog.
```verilog=
module counter
(
input wire clk,
input wire rst_n,
input wire clr,
input wire start,
output wire [3:0] q
);
reg [3:0] cnt_reg;
always @(posedge clk)
begin
if (!rst_n || clr)
begin
cnt_reg <= 0;
end
else if (start)
begin
cnt_reg <= cnt_reg + 1;
end
else if (cnt_reg >= 1 && cnt_reg <= 4)
begin
cnt_reg <= cnt_reg + 1;
end
else if (cnt_reg >= 5)
begin
cnt_reg <= 0;
end
end
assign q = cnt_reg;
endmodule
```
The following code is the testbench for the counter.
```verilog=
`timescale 1ns / 1ps
module counter_tb();
localparam T = 10;
reg clk, rst_n, clr, start;
wire [7:0] q;
counter dut(.clk(clk), .rst_n(rst_n), .clr(clr), .start(start), .q(q));
always
begin
clk = 0;
#(T/2);
clk = 1;
#(T/2);
end
initial
begin
clr = 0;
start = 0;
rst_n = 0; #T;
rst_n = 1; #T;
start = 1; #T;
start = 0;
end
endmodule
```
#### 5.3. Counter as State Machine
Suppose we want to create a controller for a system that consists of 1 RAM for data input, 1 PE, and 1 RAM for data output. The RAM has two signals that need to be controlled, which are enable (en_rd, en_wr) and address (addr_rd, addr_wr) signals. The PE has one signal that needs to be controlled, which is enable (en_pe) signal. The requirements of the timing diagram are shown below.


In addition to that, there are status signals, which are ready and done_tick. The counter starts when the start signal is 1. We can implement these requirements using a counter module. The following figure shows the circuit implemented for that purpose.
The circuit consists of three counters. One for FSM, and the others for address reading and writing. Then, from the counter FSM output, we can build the output logic. The logic uses comparators and 2-to-1 multiplexers. The logic is based on the current counter FSM value, which starts from 1 to 7. Based on that counter value and output logic condition, the output signals are generated.

This is the implementation of the counter as FSM in Verilog. In this module, we create both combinational and sequential circuits. We use both continuous and procedural assignments.
```verilog=
module counter_fsm
(
input wire clk,
input wire rst_n,
input wire clr,
input wire start,
output wire done_tick,
output wire ready,
output wire en_rd,
output wire [3:0] addr_rd,
output wire en_pe,
output wire en_wr,
output wire [3:0] addr_wr
);
reg [3:0] cnt_fsm_reg;
reg [3:0] cnt_addr_rd_reg;
reg [3:0] cnt_addr_wr_reg;
wire start_cnt_addr_rd;
wire start_cnt_addr_wr;
// Main counter as FSM
always @(posedge clk)
begin
if (!rst_n || clr)
begin
cnt_fsm_reg <= 0;
end
else if (start)
begin
cnt_fsm_reg <= cnt_fsm_reg + 1;
end
else if (cnt_fsm_reg >= 1 && cnt_fsm_reg <= 6)
begin
cnt_fsm_reg <= cnt_fsm_reg + 1;
end
else if (cnt_fsm_reg >= 7)
begin
cnt_fsm_reg <= 0;
end
end
// Control to start address read counter
assign start_cnt_addr_rd = (cnt_fsm_reg == 1) ? 1 : 0;
// Control to enable read
assign en_rd = ((cnt_fsm_reg >= 1) & (cnt_fsm_reg <= 4)) ? 1 : 0;
// Control to enable pe
assign en_pe = ((cnt_fsm_reg >= 2) & (cnt_fsm_reg <= 5)) ? 1 : 0;
// Control to start address write counter
assign start_cnt_addr_wr = (cnt_fsm_reg == 3) ? 1 : 0;
// Control to enable write
assign en_wr = ((cnt_fsm_reg >= 3) & (cnt_fsm_reg <= 6)) ? 1 : 0;
// Status done
assign done_tick = (cnt_fsm_reg == 7) ? 1 : 0;
// Status ready
assign ready = (cnt_fsm_reg == 0) ? 1 : 0;
// Additional counter for address read
always @(posedge clk)
begin
if (!rst_n)
begin
cnt_addr_rd_reg <= 0;
end
else if (start_cnt_addr_rd)
begin
cnt_addr_rd_reg <= cnt_addr_rd_reg + 1;
end
else if (cnt_addr_rd_reg >= 1 && cnt_addr_rd_reg <= 2)
begin
cnt_addr_rd_reg <= cnt_addr_rd_reg + 1;
end
else if (cnt_addr_rd_reg >= 3)
begin
cnt_addr_rd_reg <= 0;
end
end
// Address read output
assign addr_rd = cnt_addr_rd_reg;
// Additional counter for address write
always @(posedge clk)
begin
if (!rst_n)
begin
cnt_addr_wr_reg <= 0;
end
else if (start_cnt_addr_wr)
begin
cnt_addr_wr_reg <= cnt_addr_wr_reg + 1;
end
else if (cnt_addr_wr_reg >= 1 && cnt_addr_wr_reg <= 2)
begin
cnt_addr_wr_reg <= cnt_addr_wr_reg + 1;
end
else if (cnt_addr_wr_reg >= 3)
begin
cnt_addr_wr_reg <= 0;
end
end
// Address write output
assign addr_wr = cnt_addr_wr_reg;
endmodule
```
The following code is the testbench for the counter as FSM.
```verilog=
`timescale 1ns / 1ps
module counter_fsm_tb();
localparam T = 10;
reg clk, rst_n, clr, start;
wire en_rd, en_pe, en_wr;
wire [3:0] addr_rd, addr_wr;
counter_fsm dut (.clk(clk), .rst_n(rst_n), .clr(clr), .start(start),
.en_rd(en_rd), .addr_rd(addr_rd), .en_pe(en_pe), .en_wr(en_wr),
.addr_wr(addr_wr));
always
begin
clk = 0;
#(T/2);
clk = 1;
#(T/2);
end
initial
begin
clr = 0;
start = 0;
rst_n = 0; #T;
rst_n = 1; #T;
start = 1; #T;
start = 0;
end
endmodule
```