How to Design FSM in Verilog: Simple Guide with Example
To design a
FSM in Verilog, define states using parameter or typedef enum, create registers for current and next states, and use an always block to update states on clock edges. Use a combinational block to decide the next state based on inputs and current state.Syntax
An FSM in Verilog typically has three parts:
- State definition: Use
parameterortypedef enumto name states. - State registers: Hold the current and next state.
- State transition logic: Use
always @(posedge clk)to update current state and a combinationalalways @(*)block to decide next state.
verilog
typedef enum logic [1:0] { IDLE = 2'b00, STATE1 = 2'b01, STATE2 = 2'b10 } state_t; state_t current_state, next_state; // State update always @(posedge clk or posedge reset) begin if (reset) current_state <= IDLE; else current_state <= next_state; end // Next state logic always @(*) begin case (current_state) IDLE: next_state = (start) ? STATE1 : IDLE; STATE1: next_state = (cond) ? STATE2 : IDLE; STATE2: next_state = IDLE; default: next_state = IDLE; endcase end
Example
This example shows a simple FSM with three states: IDLE, STATE1, and STATE2. It transitions based on input signals start and cond. The FSM resets to IDLE on reset.
verilog
module simple_fsm(
input logic clk,
input logic reset,
input logic start,
input logic cond,
output logic [1:0] state_out
);
typedef enum logic [1:0] {
IDLE = 2'b00,
STATE1 = 2'b01,
STATE2 = 2'b10
} state_t;
state_t current_state, next_state;
// State update
always_ff @(posedge clk or posedge reset) begin
if (reset)
current_state <= IDLE;
else
current_state <= next_state;
end
// Next state logic
always_comb begin
case (current_state)
IDLE: next_state = (start) ? STATE1 : IDLE;
STATE1: next_state = (cond) ? STATE2 : IDLE;
STATE2: next_state = IDLE;
default: next_state = IDLE;
endcase
end
assign state_out = current_state;
endmoduleCommon Pitfalls
- Missing reset logic: Without reset, FSM may start in unknown state.
- Incorrect sensitivity list: Use
always_ff @(posedge clk or posedge reset)for state updates andalways_combfor next state logic to avoid latches. - Not covering all states in
case: Always include adefaultcase to avoid inferred latches. - Mixing blocking and non-blocking assignments: Use non-blocking (
<=) in sequential blocks and blocking (=) in combinational blocks.
verilog
/* Wrong: Missing reset and blocking assignment in sequential block */ always @(posedge clk) begin current_state <= next_state; // changed to non-blocking assignment end /* Correct: Use non-blocking and reset */ always_ff @(posedge clk or posedge reset) begin if (reset) current_state <= IDLE; else current_state <= next_state; end
Quick Reference
| Concept | Description |
|---|---|
| State Definition | Use parameter or typedef enum to name states clearly. |
| State Registers | Use registers to hold current and next state. |
| Sequential Block | Update current state on clock edge with reset. |
| Combinational Block | Decide next state based on inputs and current state. |
| Reset | Always include reset to initialize FSM state. |
| Default Case | Include default in case statements to avoid latches. |
Key Takeaways
Define states clearly using typedef enum or parameters for readability.
Use non-blocking assignments in sequential always blocks for state updates.
Always include reset logic to initialize the FSM safely.
Use combinational always blocks for next state logic with full case coverage.
Avoid mixing blocking and non-blocking assignments to prevent simulation mismatches.