The three-block FSM coding style helps you write clear and organized state machines. It separates the logic into three parts: state register, next state logic, and output logic.
Three-block FSM coding style in Verilog
always_ff @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end always_comb begin case(state) IDLE: if (start) next_state = RUN; else next_state = IDLE; RUN: if (stop) next_state = IDLE; else next_state = RUN; default: next_state = IDLE; endcase end always_comb begin case(state) IDLE: output_signal = 0; RUN: output_signal = 1; default: output_signal = 0; endcase end
The first block updates the current state on clock edges.
The second block decides the next state based on current state and inputs.
typedef enum logic [1:0] {IDLE, RUN, STOP} state_t; state_t state, next_state;
always_ff @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end
always_comb begin
case(state)
IDLE: next_state = start ? RUN : IDLE;
RUN: next_state = stop ? IDLE : RUN;
default: next_state = IDLE;
endcase
endalways_comb begin
case(state)
IDLE: output_signal = 0;
RUN: output_signal = 1;
default: output_signal = 0;
endcase
endThis example shows a simple FSM with two states: IDLE and RUN. It starts running when start is high and stops when stop is high. The output running is 1 only in the RUN state.
module fsm_three_block( input logic clk, reset, start, stop, output logic running ); typedef enum logic [1:0] {IDLE, RUN} state_t; state_t state, next_state; // State register block always_ff @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end // Next state logic block always_comb begin case(state) IDLE: next_state = start ? RUN : IDLE; RUN: next_state = stop ? IDLE : RUN; default: next_state = IDLE; endcase end // Output logic block always_comb begin case(state) IDLE: running = 0; RUN: running = 1; default: running = 0; endcase end endmodule
Use always_ff for sequential logic (state updates) and always_comb for combinational logic (next state and outputs).
Keep the three blocks separate to avoid mixing logic and make debugging easier.
Resetting the state ensures the FSM starts in a known state.
The three-block FSM style splits your state machine into state register, next state logic, and output logic.
This separation makes your code easier to read, maintain, and debug.
Use always_ff for state updates and always_comb for next state and output decisions.