ASIC-WORLD Verilog(13) State Machine FSM

Write in front

Before I prepared to write some simple verilog tutorials, I referred to many materials–this set of verilog tutorials on the Asic-World website is one of them. This set of tutorials is very well written, but it is not in Chinese, so I have to boldly translate it (adding my own understanding) and share it with everyone.

This is the original text of the website: Verilog Tutorial

This is the series navigation: Verilog tutorial series article navigation

Introduction to Finite State Machine FSM

State machines (FSM) are at the heart of many digital designs. Counters are a simple form of FSM. When I was learning Verilog, I used to wonder “how to code a FSM in Verilog” and “what is the best way to code it”. Next I will try to answer these two questions.

State machine type

There are two types of state machines classified according to their output type. The first is a Moore state machine, whose output is only a function of the current state; the second is a Mealy state machine, whose output is a function of the current state and the input.

Moore State Machine

Mealy state machine

State machines can also be classified based on the state encoding used. Encoding type is also a key factor in determining the speed and complexity of FSM. Binary encoding, Gray code, and one-hot code are the most common FSM state encoding types.

State machine modeling

One thing to remember when coding an FSM: combinational logic and sequential logic should be in two different always blocks. In the above two figures, next state logic is always combinational logic; while state logic and output logic are sequential logic. Any asynchronous signals to the next state logic must be synchronized before being fed to the FSM. You should try to keep the state machine FSM in a separate Verilog file.

Using constant declarations such as parameter or `define to define the state of the FSM makes the code more readable and easier to manage.

Example: Arbiter

Next, we will use the arbiter as a case to see how to implement a complete FSM.

The FSM code should contain three parts:

  • Status coding part
  • Combinational logic part
  • Sequential logic part

Status coding

There are many ways to encode status, the most commonly used are:

  • Binary Encoding
  • One Hot Encoding
  • Gray Encoding

One Hot Encoding

parameter [4:0] IDLE = 5'b0_0001;
parameter [4:0] GNT0 = 5'b0_0010;
parameter [4:0] GNT1 = 5'b0_0100;
parameter [4:0] GNT2 = 5'b0_1000;
parameter [4:0] GNT3 = 5'b1_0000;

Binary Encoding

parameter [2:0] IDLE = 3'b000;
parameter [2:0] GNT0 = 3'b001;
parameter [2:0] GNT1 = 3'b010;
parameter [2:0] GNT2 = 3'b011;
parameter [2:0] GNT3 = 3'b100;

Gray Encoding

parameter [2:0] IDLE = 3'b000;
parameter [2:0] GNT0 = 3'b001;
parameter [2:0] GNT1 = 3'b011;
parameter [2:0] GNT2 = 3'b010;
parameter [2:0] GNT3 = 3'b110;

Combination logic part

This part can be implemented using functions, assign statements or always blocks.

always @ (state or req_0 or req_1 or req_2 or req_3)
begin
  next_state = 0;
  case(state)
    IDLE: if (req_0 == 1'b1) begin
  next_state = GNT0;
           end else if (req_1 == 1'b1) begin
  next_state= GNT1;
           end else if (req_2 == 1'b1) begin
  next_state= GNT2;
           end else if (req_3 == 1'b1) begin
  next_state= GNT3;
end else begin
  next_state = IDLE;
           end
    GNT0: if (req_0 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT0;
end
    GNT1: if (req_1 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT1;
end
    GNT2: if (req_2 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT2;
end
    GNT3: if (req_3 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT3;
end
   default : next_state = IDLE;
  endcase
end

Sequential logic part

This part can only be implemented using edge-sensitive logic such as the always block with posedge clock or negedge clock.

always @ (posedge clock)
begin : OUTPUT_LOGIC
  if (reset == 1'b1) begin
    gnt_0 <= #1 1'b0;
    gnt_1 <= #1 1'b0;
    gnt_2 <= #1 1'b0;
    gnt_3 <= #1 1'b0;
    state <= #1 IDLE;
  end else begin
    state <= #1 next_state;
    case(state)
       IDLE: begin
                gnt_0 <= #1 1'b0;
                gnt_1 <= #1 1'b0;
                gnt_2 <= #1 1'b0;
                gnt_3 <= #1 1'b0;
end
  GNT0: begin
  gnt_0 <= #1 1'b1;
  end
        GNT1: begin
                 gnt_1 <= #1 1'b1;
               end
        GNT2: begin
                 gnt_2 <= #1 1'b1;
               end
        GNT3: begin
                 gnt_3 <= #1 1'b1;
               end
     default: begin
                 state <= #1 IDLE;
               end
    endcase
  end
end

Complete FSM code using binary encoding

module fsm_full(
clock , // Clock
reset, // Active high reset
req_0 , // Active high request from agent 0
req_1 , // Active high request from agent 1
req_2 , // Active high request from agent 2
req_3 , // Active high request from agent 3
gnt_0 , // Active high grant to agent 0
gnt_1 , // Active high grant to agent 1
gnt_2 , // Active high grant to agent 2
gnt_3 // Active high grant to agent 3
);
// Port declaration here
input clock; // Clock
input reset; // Active high reset
input req_0; // Active high request from agent 0
input req_1; // Active high request from agent 1
input req_2; // Active high request from agent 2
input req_3; // Active high request from agent 3
output gnt_0; // Active high grant to agent 0
output gnt_1; // Active high grant to agent 1
output gnt_2; // Active high grant to agent 2
output gnt_3; // Active high grant to agent

// Internal Variables
reg gnt_0; // Active high grant to agent 0
reg gnt_1; // Active high grant to agent 1
reg gnt_2; // Active high grant to agent 2
reg gnt_3; // Active high grant to agent

parameter [2:0] IDLE = 3'b000;
parameter [2:0] GNT0 = 3'b001;
parameter [2:0] GNT1 = 3'b010;
parameter [2:0] GNT2 = 3'b011;
parameter [2:0] GNT3 = 3'b100;

reg [2:0] state, next_state;

always @ (state or req_0 or req_1 or req_2 or req_3)
begin
  next_state = 0;
  case(state)
    IDLE: if (req_0 == 1'b1) begin
  next_state = GNT0;
           end else if (req_1 == 1'b1) begin
  next_state= GNT1;
           end else if (req_2 == 1'b1) begin
  next_state= GNT2;
           end else if (req_3 == 1'b1) begin
  next_state= GNT3;
end else begin
  next_state = IDLE;
           end
    GNT0: if (req_0 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT0;
end
    GNT1: if (req_1 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT1;
end
    GNT2: if (req_2 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT2;
end
    GNT3: if (req_3 == 1'b0) begin
  next_state = IDLE;
           end else begin
next_state = GNT3;
end
   default : next_state = IDLE;
  endcase
end

always @ (posedge clock)
begin : OUTPUT_LOGIC
  if (reset) begin
    gnt_0 <= #1 1'b0;
    gnt_1 <= #1 1'b0;
    gnt_2 <= #1 1'b0;
    gnt_3 <= #1 1'b0;
    state <= #1 IDLE;
  end else begin
    state <= #1 next_state;
    case(state)
IDLE: begin
                gnt_0 <= #1 1'b0;
                gnt_1 <= #1 1'b0;
                gnt_2 <= #1 1'b0;
                gnt_3 <= #1 1'b0;
end
  GNT0: begin
  gnt_0 <= #1 1'b1;
  end
        GNT1: begin
                 gnt_1 <= #1 1'b1;
               end
        GNT2: begin
                 gnt_2 <= #1 1'b1;
               end
        GNT3: begin
                 gnt_3 <= #1 1'b1;
               end
     default: begin
                 state <= #1 IDLE;
               end
    endcase
  end
end

endmodule

Test script

`include "fsm_full.v"

module fsm_full_tb();
reg clock , reset ;
reg req_0 , req_1 , req_2 , req_3;
wire gnt_0 , gnt_1 , gnt_2 , gnt_3 ;

initial begin
  $display("Time\t R0 R1 R2 R3 G0 G1 G2 G3");
  $monitor("%g\t %b %b %b %b %b %b %b %b",
    $time, req_0, req_1, req_2, req_3, gnt_0, gnt_1, gnt_2, gnt_3);
  clock = 0;
  reset = 0;
  req_0 = 0;
  req_1 = 0;
  req_2 = 0;
  req_3 = 0;
  #10 reset = 1;
  #10 reset = 0;
  #10 req_0 = 1;
  #20 req_0 = 0;
  #10 req_1 = 1;
  #20 req_1 = 0;
  #10 req_2 = 1;
  #20 req_2 = 0;
  #10 req_3 = 1;
  #20 req_3 = 0;
  #10 $finish;
end

always
 #2 clock = ~clock;


fsm_full U_fsm_full(
clock , // Clock
reset, // Active high reset
req_0 , // Active high request from agent 0
req_1 , // Active high request from agent 1
req_2 , // Active high request from agent 2
req_3 , // Active high request from agent 3
gnt_0 , // Active high grant to agent 0
gnt_1 , // Active high grant to agent 1
gnt_2 , // Active high grant to agent 2
gnt_3 // Active high grant to agent 3
);

endmodule

Simulation results

  • If you have any questions, you can communicate with me in the comment area!
  • This article was originally created by Lonely Dandao and was first published on the CSDN platform, blog homepage: wuzhikai.blog.csdn.net
  • Your support is my biggest motivation to continue creating! If this article is helpful to you, please like it, comment it and collect it!