Types of FSMs

There are two classifications of state machines based on the nature of their output generation:

  • Moore: In this type, the outputs depend solely on the current state.
  • Mealy: In contrast, this type generates one or more outputs that are influenced by both the current state and one or more inputs.

Beyond categorizing state machines by their output generation methods, they are also frequently classified based on the state encoding used. State encoding refers to how the different states of a state machine are represented in binary form.

  • Binary: Each state is represented using standard binary numbers (e.g., 00, 01, 10, 11).
  • One-Hot: Each state is represented by a binary vector where only one bit is '1' (hot) and all others are '0'.

Verilog FSM Structure

FSMs in Verilog can be written in either a single always block or two always blocks.

The two always block method is most recommended for its straightforward structure and ease of understanding and consists of:

  • A sequential or clocked always block for present state logic
  • A combinational always block for next state logic
verilog fsm

Output assignments can be handled in two ways:

  • Included within the combinational next-state always block
  • Implemented as separate continuous assignments

Sequential Always Block

Note that the state of a finite state machine (FSM) changes only at the clock edge.


always @ (posedge clk) begin
  // If reset is asserted, go back to IDLE state
  if (! resetn) begin
    cur_state <= IDLE;

  // Else transition to the next state
  end else begin 
    cur_state <= next_state;
  end 
end

Always use only non-blocking assignments in the sequential always block !

Verilog nonblocking assignments emulate the behavior of pipelined registers found in actual hardware, effectively reducing the likelihood of race conditions in Verilog.

Combinational Always Block

Create a combinational always block to update the next state value.

This block should be triggered by a sensitivity list that includes the state register from the synchronous always block as well as all inputs to the state machine. Immediately after the sensitivity list, provide a default assignment for the next state.



// Combinational always block for next state logic
always @(*) begin
    // Default next state assignment
    next_state = IDLE; 

    case (state)
        IDLE: begin
                if (input_signal) 
                  next_state = STATE_1; // Transition to STATE_1 on input_signal
              end
        
        STATE_1:  begin
                    if (!input_signal) 
                      next_state = STATE_2; // Transition to STATE_2 if input_signal is low
                  end
        
        STATE_2:  next_state = IDLE; // Transition back to IDLE        
        default:  next_state = IDLE; // Fallback to default state
    endcase
end

Always use blocking assignments in combinational always blocks !

Output Generation

Implement the output logic either within the combinational logic always block or as a separate block of continuous assignments.

When incorporating output assignments into the combinational always block, start with default output assignments at the beginning of the always block, and then update the relevant output assignments within the case statement. They can also be organized into Verilog tasks with descriptive names.

 
    reset_op_signals();  // Assign default values
      
    case (state)
        IDLE: begin
                if (input_signal) begin
                  next_state = STATE_1; 
                  output_signal = 0;          // Assign output signal   
                  reset_op_signals();         // Or call function to reset outputs
                end
              end
        
        STATE_1:  begin
                    if (!input_signal) begin
                      next_state = STATE_2;  
                      output_signal = 1;           // Assign output signal
                      change_op_signals(STATE_2);  // or call function to update output
                    end
                  end

         // Rest of the state descriptions
      endcase

If it is coded as a separate block of continuous assignments, it will be duplicate effort and verbose to handle output conditions for each appropriate state which could have been taken care inside the case statement.

  
   assign  op_signal = (cur_state == STATE_1) ? 1 : 0;   

Registered outputs can be incorporated into the Verilog code by using nonblocking assignments within a sequential always block. The FSM can be implemented with either a single sequential always block or by adding a second sequential always block to the design.

Elaborated Schematic

Note that the sequential logic that represents the current_state is just a FF and the combinational logic that decides next_state is a couple of multiplexers.

verilog fsm elaborated view

The two-always block method effectively partitions the Verilog code into its main functional blocks, mirroring the classical Finite State Machine (FSM) structure:

  • Clocked Present State Logic
  • Next State Combinational Logic
  • Output Combinational Logic

This clear separation of concerns makes the two-always block method highly readable and maintainable, aligning well with the conceptual model of FSMs.

Click here for Pattern Detector Verilog FSM example !