Lecture 12 – FSM I

Ryan Robucci

1. State Machines Basics

Mealy Machine

gen-mealy.svg

Moore Machine

gen-moore.svg

2. References

3. Implementation of Mealy and Moore Machines

20240326190932.png

4. State-Machine Implementation

20240326191122.png

  • All Finite State Machines can be partitioned into a combinatorial and sequential parts
  • Often these two pieces are coded in separate code blocks, but they may also be combined sometimes
  • Note: some simple register-specific operations such a synchronous reset are coded in either the combination or the sequential blocks, but are often coded in the sequential block to indicate selection of register configuration. An asynchronous clear should be part of the sequential block.

5. State-Machine Verilog Implementation

module FSM (clk, clear, x,y);

input logic clk, clear;
input logic [2:0] x;
output logic [1:0] y;

// Declare the symbolic names for states
          //Verilog: localparam [6:0] S1 = 7'b0000001,S2 = 7'b0000010, S7 = 7'b1000000;
  typedef enum int {S0,S1,S2} state_t;



// Declare current state and next state variables
  //Verilog: reg [2:0] CS,NS;
  state_t CS,NS;


always_ff @ (posedge clk or posedge clear) begin
  if (clear == 1'b1) CS <= S0;
  else CS <= NS;
end

always_comb begin //always @ (CS, x)
  case (CS)
    S0 : begin
         y = 2'b00;
         if (x[2] && ~x[1] && x[0])
           NS = S1;
         else if (x[2] && x[1] && ~x[0])
           NS = S2;
         else
           NS = S0;
    end
    S1 : begin
         y = 2'b10;

    ...
end

6. Mealy Implementation


module FSM (clk, clear, x,y);

input logic clk, clear;
input logic [2:0] x;
output logic [1:0] y;

// States
typedef enum int {S0,S1,S2} state_t;


// Declare current state and next state variables
state_t CS,NS;


always_ff @ (posedge CLOCK or posedge clear) begin
  if (clear == 1'b1) CS <= S1;
  else CS <= NS;
end

always_comb begin //always @ (CS, x)
  case (CS)
    S1 : begin
         y = {x[2] , ~x[1] && x[0]};
         if (x[2] && ~x[1] && x[0])
           NS = S2;
         else if (x[2] && x[1] && ~x[0])
           NS = S4;
         else
           NS = S1;
    end
    S2 : begin
         y = 2'b10;

    ...


  • every output bit must be well-defined for every case and input to avoid latches
  • for NS, every output bit is set in every case to avoid latches

7. SystemVerilog FSM State Register

Verilog

reg [7:0] CS,NS; //reg!=register
localparam S_init   = 8'b00000000;
localparam S_start0 = 8'b00000001;
localparam S_start1 = 8'b00000010;

SystemVerilog

enum int {S_init, S_start0,S_start1} state_t;
state_t CS,NS;

SystemVerilog enum:

  • meaningful enum symbols displayed in waveform viewers and loggers
  • Symbol accessed as string through member function name():

    $strobe("State %s %0d",CS.name(),CS);
    
  • When automatic FSM state reencoding is used, shouldn't put much human effort into providing encodings
    • using localparam to provide state encodings requires significant effort and careful use
    • later: discuss that with default settings, many synthesizers replace user-provided encodings for FSM states
    • therefore use of enum int seems appropriate when finally using synthesizer-generated encodings

8. Single Always Block Style for Registered Output Logic (Registered-Output Mealy)

always_ff @ (posedge CLOCK or posedge CLEAR) begin: FSM
  logic _temp;

  if (CLEAR == 1'b1) begin
    CS <= S1;
  end else begin 
    case (CS) 
      S1 : begin 
        _temp = ~x[1];                     //intermediate logic (blocking assignment)
        y  <= {x[2] , _temp & x[0]};       //register intent (non-blocking assignment)
        if (x[2] && _temp && x[0])  
          CS <= S2;                        //register intent (non-blocking assignment)
        else if (x[2] && x[1] && ~x[0]) 
          CS <= S4; 
        else 
          CS <= S1;
      end
      S2 : begin 
          y  <= {x[1] && ~x[1] , x[0]};   
         . 
         . 
         . 
  • Embedded combination circuit signal assignments ended with blocking assignment and thus encode "immediate" effect. All consumers of blocking assignment results should be within this code block. Even within the block, no consumer should rely on a value assigned from a blocking statement in a previous trigger event.
  • Remember, any variable written to inside an edge-triggered block can become a register regardless of the use of blocking or non-blocking…consider every output variable, combinational and sequential, in every case and branch of decision tree and make sure assignments are always made to avoid latches

9. Coding Style for State Machines

🛰️ Registered Output with Three-Always Block Style

  • Registered output can cause “cycle delays” so some output transitions need to be coded along with the state transition into a state rather than with the state they are supposed to coincide with (discuss output on prev. slide)
  • Sometimes this feels like you’re coding outputs in the “previous state” or coding output ahead of time to account for register delay. I refer to it as coding the output along with the state transition it coincides with. This leads to additional lines of code as you need to code each output logic possibly for every transition to a state rather than once per state
  • To avoid this “code bloat”, yet another approach is to code the registered outputs in a separate block. This leads to three blocks:
    • Combinatorial Next State Logic along with any combinatorial outputs
    • Sequential State Register
    • Sequential Registered Outputs according to the destination (next) state from the combinatorial Block.
  • Good contrasting examples can be found here: http://www.sunburst-design.com/papers/CummingsSNUG2003SJ_SystemVerilogFSM.pdf

10. Example State-Machine: An Arbitrator

Block Diagram

gen-arb.svg

Example Operation Timing Diagram

  • Assume peripherals need a start signal for two-clock cycles
    • in the next cycle they present busy as low
    • then in the following cycle after they present busy as high and hold it until it coincides with a new result

arb-wave.svg

Statemachine

  • Using more states simplifies output logic

20240326195939.png

  • Using fewer states requires more output logic and, in the code shown effectively embeds extended state information in additional registers

20240326195950.png

Code (In-Class)

Code (using registered Outputs With Single Always Block)

module control_with_state_machine2(
   input  logic clk,
   input  logic rst,
   output logic startA,     // start signal to   peripheral  A
   output logic startB,     // start signal to   peripheral  B
   input  logic busyA,      // busy  signal from peripheral  A
   input  logic busyB,      // busy  signal from peripheral  B
   output logic ready,      // ready signal to   primary
   input  logic sel0A1B,    // peripheral select
   input  logic start       // go    signal from primary
);

enum int {S_init, S_start0,S_start1} state_t
state_t CS,NS;


always_ff @ (posedge clk) begin
  if (rst == 1)
    CS<=S_init;
  else
    case (CS)
    S_init: begin
      if (start == 1) begin
        startA <= ~sel_0A1B;
        startB <=  sel_0A1B;
        sel_0A1B_saved<= sel_0A1B;
        CS<=S_start0;
      end else begin
        startA <= 0;
        startB <= 0;
        CS<=S_init;
      end
    end
    S_start0: begin
        //startA <= startA;
        //startB <= startB;
       CS<=S_start1;
    end
    S_start1: begin
        startA <= 0;
        startB <= 0;
        CS<=S_wait_for_result;
    end
    S_wait_for_result: begin
       automatic bit [15:0] _result16;
       startA <= 0;
       startB <= 0;
       if (~sel_0A1B_saved && ~busyA || ~sel_0A1B_saved && ~busyB) begin
          startCS<=S_result_H;
          if (~sel_0A1B_saved) begin
             _result16 = resultA;
          end else begin
             _result16 = resultB;
          end
          result <= {result[31:16],_result16}
       end
    end
    S_result_H: begin
       automatic bit [15:0] _result16; 
       if (~sel_0A1B_saved) begin
          _result16 = resultA;
       end else begin
          _result16 = resultB;
       end
       result <= {_result16,result[15:0]}
       ready <= 1;
    end
    endcase
end
endmodule

NOTE FSM to tackle Design Complexity

  • this is a good point to consider why we build state machines and coding hardware HDL vs software
  • a key advantage of a state machine for a logic designer is that the complexity of a large task can be broken down into smaller problems represented by the work done in each state
  • unfortunately the hardware designer must be critical of the synthesizer, because the value of hardware itself is in optimization more often than in software which is more often focused on function
  • this splits the mind of the designer and makes the overall design task more challenging and time-consuming
  • software optimization tools are mature and displace the need for humans to spend time on optimizations, while hardware design tools are maturing

Internal Timing Diagram for FSM

Place holder for in-class timing diagram. Key concepts:

  • Identification of implied combinatorial signals including register inputs (outputs and state (NS))
  • Arrival of input changes versus response timing
  • Coincidence of Code and Output Timing

timing-diagram-fsm.svg

11. Registered Outputs 3-Always-Block Style

module control_with_state_machine2(
   input  logic clk,
   input  logic rst,
   output logic startA,     //start signal to peripheral A
   output logic startB,     //start signal to peripheral B
   input  logic busyA,      //busy signal from peripheral A
   input  logic busyB,      //busy signal from peripheral B
   output logic ready,      //ready signal to primary
   input  logic sel_0A1B,    //go signal from primary
   input  logic start        //go signal from primary
);

enum int {S_init, S_start0,S_start1} state_t
state_t CS,NS;

assign ready = ~(sel_0A1B?busyB_n:busyA_n); // extra combinational logic outside state machine

  always_ff @ (posedge clk) begin
    if (rst == 1)
      CS<=S_init;
    else
      CS<=NS;
  end

  always_comb begin
     NS = CS;
     case (CS)
    S_init: begin
       if (go) begin
          NS = S_start0;
       end
    end
    S_start0:
      NS = S_start1;
    S_start1:
      NS = S_init;
      endcase
  end

  always_ff @ (posedge clk) begin
     case (NS)
       S_init:
         startA <= 0;   
         startB <= 0;   
       S_start0:
         startA <= ~selAnB;
         startB <= selAnB;
       S_start1:
         startA <= startA;  
         startB <= startB;  
      endcase
  end


endmodule
  • also need to consider appropriate resets and defaults logic

12. When is registered-output not appropriate?

Note that the specification from the following timing diagram could not be satisfied by registered logic, since values are passed through the interface intra-cycle, (within the same cycle, rather than only from one cycle to the next)

arb-wave.svg

arb-wave-comb.svg

13. Finite State Machine (FSM)

  • Characterized by
    • A set of states
    • A set of inputs and outputs
    • A state transition function
    • An output function
  • Hardware Implementation
    • Current State held in a register
    • Any additional status information held in status register
    • Next-State and State Control Logic Determines next state and control signals based on registers
    • Datapath implements operations on data under control of sate control logic

Author: Dr. Ryan Robucci

Created: 2025-04-16 Wed 10:18

Validate