---
# System prepended metadata

title: 'Verilog Tutorial 4: RT Level Finite State Machine'
tags: [ZYNQ]

---

# Verilog 4: RT Level Finite State Machine

### 1. FSM Design Methodology

A finite state machine (FSM) is used to model a system that transits among a finite number of internal states. The transitions depend on the current state and external input. Unlike a regular sequential circuit, the state transitions of an FSM **do not exhibit a simple, repetitive pattern.**

![fsm_diagram](https://hackmd.io/_uploads/BkxvmVTZ-l.jpg =60%x)


Finite State Machines (FSM) are a **fundamental building block** in digital design because they provide **a structured, systematic, and predictable method** for designing sequential logic circuits.

### 2. Mealy and Moore Outputs

The basic block diagram of synchronous FSM is similar to the regular sequential circuit, as shown in the following figure. It consists of a state register, next-state logic, and output logic.

- An FSM is known as a **Moore** machine if the output is **only a function of state**.
- An FSM is known as a **Mealy** machine if the output is **a function of state and external input**.

![Screenshot 2025-12-01 144354](https://hackmd.io/_uploads/BJVUDT9-Ze.png)

### 3. FSM Representation

An FSM is usually specified by an abstract **state diagram** or **algorithmic state machine (ASM)** chart. 

The following figure shows an example of a state diagram that consists of a single node and its transition arcs. The arc is taken when the corresponding expression is evaluated true. The Moore output value is placed inside the circle. The Mealy output is placed with the transition arcs.

![Screenshot 2025-12-01 144525](https://hackmd.io/_uploads/r1Djw6cWWx.png =60%x)

The following figure shows an example of a ASM chart that consists of a single block. An ASM block consists of one state box and an optional network of decision boxes and conditional output boxes. A state box represents a state in an FSM, and the asserted Moore output values are listed inside the box. 

A decision box tests the input condition and determines which exit path to take, true (T) or false (F). A conditional output box lists asserted Mealy output values and is usually placed after a decision box. It indicates that the listed output signal can be activated only when the corresponding condition in the decision box is met.

![Screenshot 2025-12-01 144603](https://hackmd.io/_uploads/By06PT9ZWl.png =50%x)

The following figure shows an example of a state diagram:

![Screenshot 2025-12-01 144710](https://hackmd.io/_uploads/BJGHOaqZZl.png =40%x)

In this example, we consider a simple FSM example. The FSM is represented both using a state diagram and an ASM chart as in the following figure. It consists of three states and both Mealy output x, and Moore output y. The inputs to the FSM are a and b.

The following figure shows an example of an ASM diagram

![Screenshot 2025-12-01 144736](https://hackmd.io/_uploads/SyzBOT5--x.png =50%x)


### 4. Register Transfer (RT) Operation

#### 4.1 Single RT Operation

An RT operation specifies data manipulation and transfer for a single destination register. It is represented by the notation

$$r_{dest}\leftarrow f(r_{src1}, r_{src2}, ..., r_{srcn})$$

where
- $r_{dest}$ is the destination register,
- $r_{src1}$ is the source registers 1
- $r_{src2}$ is the source registers 2
- $r_{srcn}$ is the source registers n
- $f(.)$ is mathematical function realized by a combinational circuit

The notation indicates that the contents of the source registers are fed to the $f(.)$ function, which is realized by a combinational circuit, and the result is passed to the input of the destination register and stored in the destination register **at the next rising edge of the clock**.

Following are several representative RT operations and the synthesized circuit. It consist of **current state and next state**. Next state will become current state at the rising edge of the clock.

A constant 0 is stored in $r_1$ register **at the next rising edge of the clock**.
$$r_1 \leftarrow 0$$

![image](https://hackmd.io/_uploads/BJ4ZIV6bZl.png =40%x)

The Verilog code for the circuit:

```verilog
reg [7:0] r1_reg, r1_next;

always @(posedge clk)
begin
    if (!rst_n)
        r1_reg <= 0;
    else
        r1_reg <= r1_next;
end

always @(*)
begin
    r1_next = 0;
end
```

The summation of the $r_1$ and $r_2$ registers is written to the $r_1$ register **at the next rising edge of the clock**.
$$r_1 \leftarrow r_1 + r_2$$

![image](https://hackmd.io/_uploads/HJ1mI46-bx.png =50%x)

The Verilog code for the circuit:

```verilog
reg [7:0] r1_reg, r1_next;
reg [7:0] r2_reg, r2_next;

always @(posedge clk)
begin
    if (!rst_n)
        r1_reg <= 0;
    else
        r1_reg <= r1_next;
end

always @(*)
begin
    r1_next = r1_reg + r2_reg;
end

// r2 reg ...
```

The $r_1$ register is shifted left two positions and then written back to itself **at the next rising edge of the clock**.
$$r_1 \leftarrow r_1 << 2$$

![image](https://hackmd.io/_uploads/r1KE8EabZl.png =50%x)

The Verilog code for the circuit:

```verilog
reg [7:0] r1_reg, r1_next;

always @(posedge clk)
begin
    if (!rst_n)
        r1_reg <= 0;
    else
        r1_reg <= r1_next;
end

always @(*)
begin
    r1_next = r1_reg << 2;
end
```

The content of the $r_1$ register is written back to itself **at the next rising edge of the clock**.
$$r_1 \leftarrow r_1$$

![image](https://hackmd.io/_uploads/HkJDUVpWbx.png =40%x)

The Verilog code for the circuit:

```verilog
reg [7:0] r1_reg, r1_next;

always @(posedge clk)
begin
    if (!rst_n)
        r1_reg <= 0;
    else
        r1_reg <= r1_next;
end

always @(*)
begin
    r1_next = r1_reg;
end
```

#### 4.2 Combining RT Operations

We can combine all of the RT operations to become a complex system. The resulting circuit from the examples before is become like this:

![Screenshot 2025-12-01 145922](https://hackmd.io/_uploads/B1QxiacZWe.png =70%x)

The Verilog code for the circuit:

```verilog
reg [1:0] state_reg, state_next;
reg [7:0] r1_reg, r1_next;

always @(posedge clk)
begin
    if (!rst_n) begin
        state_reg <= 0;
        r1_reg <= 0;
    end
    else begin
        state_reg <= state_next;
        r1_reg <= r1_next;
    end
end

always @(*)
begin
    state_next = state_reg;
    r1_next = r1_reg;
    case (state_reg)
        2'b00: begin
            state_next = 2'b01;
            r1_next = 0;
        end
        2'b01: begin
            state_next = 2'b10;
            r1_next = r1_reg + r2_reg;
        end
        2'b10: begin
            state_next = 2'b11;
            r1_next = r1_reg << 2;
        end
        2'b11: begin
            state_next = 2'b00;
            r1_next = r1_reg;
        end
    endcase
end
```

### 5. Design Examples

The procedure of developing code for an FSM is similar to that of a regular sequential circuit. We first separate the state register and then derive the code for the combinational next-state logic and output logic.

```verilog=
module fsm_eg_4seg
    (
        input wire        clk,
        input wire        rst_n,
        input wire        a,
        input wire        b,
        output wire [7:0] x,
        output wire [7:0] y
    );
    
    // Symbolic state declaration
    localparam [1:0] S0 = 2'b00,
                     S1 = 2'b01,
                     S2 = 2'b10;
    // Signal declaration
    reg [1:0] state_reg, state_next;

    // Segment 1: State register
    always @(posedge clk)
    begin
        if (!rst_n)
            state_reg <= S0;
        else
            state_reg <= state_next;
    end
    
    // Segment 2: Next state logic
    always @(*)
    begin
        state_next = state_reg;
        case (state_reg)
            S0: begin
                if (a == 1'b1)
                    if (b == 1'b1)
                        state_next = S2;
                    else
                        state_next = S1;
                else
                    state_next = S0;
            end
            S1: begin
                if (a == 1'b1)
                    state_next = S0;
                else
                    state_next = S1;
            end
            S2: begin
                state_next = S0;
            end
        endcase
    end

    // Segment 3: Mealy output logic
    assign x = ( ((state_reg == S0) || (state_reg == S2)) && a && b ) ?
               8'd168 : 8'd0;
    
    // Segment 4: Moore output logic
    assign y = (state_reg == S1) ? 8'd168 : 8'd0;
    
endmodule
```

```verilog=
module fsm_eg_2seg
    (
        input wire       clk,
        input wire       rst_n,
        input wire       a,
        input wire       b,
        output reg [7:0] x,
        output reg [7:0] y
    );
    
    // Symbolic state declaration
    localparam [1:0] S0 = 2'b00,
                     S1 = 2'b01,
                     S2 = 2'b10;
    // Signal declaration
    reg [1:0] state_reg, state_next;

    // Segment 1: State register
    always @(posedge clk)
    begin
        if (!rst_n)
            state_reg <= S0;
        else
            state_reg <= state_next;
    end
    
    // Segment 2: Next state logic and output logic
    always @(*)
    begin
        state_next = state_reg;
        x = 8'd0;
        y = 8'd0;
        case (state_reg)
            S0: begin
                if (a == 1'b1)
                    if (b == 1'b1)
                    begin
                        x = 8'd168;
                        state_next = S2;
                    end
                    else
                        state_next = S1;
                else
                    state_next = S0;
            end
            S1: begin
                y = 8'd168;
                if (a == 1'b1)
                    state_next = S0;
                else
                    state_next = S1;
            end
            S2: begin
                if (a && b)
                    x = 8'd168;
                state_next = S0;
            end
        endcase
    end
    
endmodule
```

The following code is the testbench for the FSM example.

```verilog=
`timescale 1ns / 1ps

module fsm_eg_4seg_tb();
    localparam T = 10;
    
    reg clk, rst_n;
    reg a, b;
    wire [7:0] x, y;

    fsm_eg_4seg dut(.clk(clk), .rst_n(rst_n), .a(a), .b(b), .x(x), .y(y));
    
    always
    begin
        clk = 0;
        #(T/2);
        clk = 1;
        #(T/2);
    end
    
    initial
    begin
        a = 0; b = 0;
    
        rst_n = 0; #T;
        rst_n = 1; #T;
        
        a = 1; b = 0; // Go to state S1
        #T;
        a = 1; b = 0; // Go back to state S0
        #T;    
        a = 1; b = 1; // Go to state S2
        #T;           
        a = 0; b = 0;        
    end
    
endmodule
```

This is the simulation result of the four segments FSM example. The Moore output y changes when the FSM enters state S1. It follows the rising edge of the clock. But the Mealy output x changes when a and b are both one. It doesn't follow the rising edge of the clock. It follows external signals. This is the difference between Moore and Mealy outputs.

![Screenshot 2025-12-01 152244](https://hackmd.io/_uploads/BJoDxA9bbl.png)

### 6. Coding Guidelines

#### 6.1 Common Verilog Mistake

Following are common errors found in combinational circuit codes:

- Variable assigned in multiple always blocks
- Incomplete sensitivity list
- Incomplete branch and incomplete output assignment
- Combinational feedback loop

**Variable assigned in multiple always blocks.** In Verilog, variables can be assigned (i.e., appear on the left-hand side) in multiple always blocks. For example, the y variable is shared by two always blocks is the following code segment:

```verilog
reg y, a, b, clear;

always @(*)
    if (clear)
        y = 1'b0;
        
always @(*)
    y = a & b;
```

Although the code is syntactically correct and can be simulated, it cannot be synthesized. Recall that each always block can be interpreted as a circuit part. The code above indicates that y is the output of both circuit parts and can be updated by each part. No physical circuit exhibits this kind of behavior and thus the code cannot be synthesized. We must group the assignment statements in a single always block, as in

```verilog
always @(*)
    if (clear)
        y = 1'b0;
    else
        y = a & b;
```

**Incomplete sensitivity list.** For a combinational circuit, the output is a function of input and thus any change in an input signal should activate the circuit. This implies that all input signals should be included in the sensitivity list. For example, a two-input and gate can be written as

```verilog
always @(a, b) // Both a and b are in the sensitivity list
    y = a & b;
```

If we forget to include b, the code becomes

```verilog
always @(a) // b missing from sensitivity list
    y = a & b;
```

Although the code is still syntactically correct, its behavior is very different. When a changes, the always block is activated and y gets the value of a&b. When b changes, the always block remains suspended since it is not "sensitive to" b and y keeps its previous value. No physical circuit exhibits this kind of behavior. Most synthesis software will issue a warning message and infer the and gate instead.

In Verilog-2001, a special notation, @(*) is introduced to implicitly include all the relevant input signals and thus eliminates this problem.

**Incomplete branch and incomplete output assignment.** The output of a combinational circuit is a function of input only and the circuit should not contain any internal state (i.e., memory). One common error with an always block is the inference of unintended memory (inferred latch) in a combinational circuit.

Consider the following code segment, which intends to describe a circuit that generates greater-than gt and equal-to eq output signals.

```verilog
always @(*)
    if (a > b)       // eq is not assigned in this branch
        gt = 1'b1;
    else if (a == b) // gt is not assigned in this branch
        eq = 1'b1;
                     // final else branch is omitted
```

Let us first examine the incomplete branch error. There is no else branch in the segment. If both the a>b and a==b expressions are false, both gt and eq are not assigned values. According to Verilog definition, they keep their previous values (i.e., the outputs depend on the internal state) and unintended latches are inferred.

The segment also has incomplete output assignment errors. For example, when the a>b expression is true, eq is not assigned a value and thus will keep its previous state. A latch will be inferred accordingly.

There are two ways to fix the errors. The first is to add the else branch and explicitly assign all output variables. The code becomes

```verilog
always @(*)
    if (a > b)
    begin
        gt = 1'b1;
        eq = 1'b0;
    end
    else if (a == b)
    begin
        gt = 1'b0;
        eq = 1'b1;
    end
    else // i.e., a < b
    begin
        gt = 1'b0;
        eq = 1'b0;    
    end
```

The alternative is to assign a default value to each variable in the beginning of the always block to cover the unspecified branch and unassigned variable. The code becomes

```verilog
always @(*)
begin
    gt = 1'b0; // Default value for gt
    eq = 1'b0; // Default value for eq
    if (a > b)
        gt = 1'b1;
    else if (a == b)
        eq = 1'b1;
end
```

Both gt and eq assume 0 if they are not assigned a value later.

The case statement experiences the same errors if some values of the [case_expr] expression are not covered by the item expressions. Consider the following code segment:

```verilog
reg [1:0] s;

always @(*)
begin
    case (s)
        2'b00: y = 1'b1;
        2'b10: y = 1'b0;
        2'b11: y = 1'b1;
    endcase
end
```

The 2'b01 value is not covered by any branch. If s assumes this combination, y will keep its previous value and an unintended latch is inferred.

To fix this error, we have to add a default value:

```verilog
always @(*)
begin
    case (s)
        2'b00: y = 1'b1;
        2'b10: y = 1'b0;
        2'b11: y = 1'b1;
        default: y = 1'b0;
    endcase
end
```

Alternatively, we can assign a default value in the beginning of the always block:

```verilog
always @(*)
begin
    y = 1'b0; // Default value for y
    case (s)
        2'b00: y = 1'b1;
        2'b10: y = 1'b0;
        2'b11: y = 1'b1;
    endcase
end
```

**Combinational feedback loop.** Combinatorial feedback loops are usually undesirable because the output will oscillate and the output is unpredictable.

![image](https://hackmd.io/_uploads/Hyb1nVpb-x.png =80%x)

#### 6.2 Guidelines
Following are the coding guidelines for the description of combinational circuits:

- Assign a variable only in a single always block.
- Use blocking statements for combinational circuits.
- Use @(*) to include all inputs automatically in the sensitivity list.
- Make sure that all branches of the if and case statements are included.
- Make sure that the outputs are assigned in all branches.
- One way to satisfy the two previous guidelines is to assign default values for outputs in the beginning of the always block.
- Think hardware, not C code.