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.
Practice
Solution
Step 1: Understand the role of each FSM block
The three-block FSM style divides the design into state storage, next state logic, and output logic.Step 2: Identify the block that stores the current state
The state register block usesalways_ffto store the current state in flip-flops.Final Answer:
The state register block using always_ff -> Option CQuick Check:
State storage = always_ff block [OK]
- Confusing next state logic with state storage
- Thinking output logic stores state
- Mixing combinational and sequential blocks
Solution
Step 1: Identify the block type for next state logic
Next state logic is combinational and should usealways_combfor clean synthesis and readability.Step 2: Match the syntax with the correct block
always_comb begin next_state = ... end usesalways_combwith next_state assignment, which is correct for next state logic.Final Answer:
always_comb begin next_state = ... end -> Option AQuick Check:
Next state logic = always_comb block [OK]
- Using always_ff for next state logic
- Mixing sensitivity lists manually
- Assigning state in next state block
state after the rising edge of clk if reset is 0 and current state is 2?typedef enum logic [1:0] {S0=0, S1=1, S2=2} state_t;
state_t state, next_state;
// State register
always_ff @(posedge clk or posedge reset) begin
if (reset) state <= S0;
else state <= next_state;
end
// Next state logic
always_comb begin
case(state)
S0: next_state = S1;
S1: next_state = S2;
S2: next_state = S0;
default: next_state = S0;
endcase
end
// Output logic (not shown)Solution
Step 1: Analyze current state and next state logic
Current state is S2 (2). According to next state logic, from S2 next_state = S0.Step 2: Determine state after clock edge with reset=0
Since reset=0, state updates to next_state, which is S0 (0).Final Answer:
S0 (0) -> Option AQuick Check:
From S2, next_state = S0, so state = S0 after clk [OK]
- Confusing current and next state
- Ignoring reset condition
- Assuming state stays the same
always_ff @(posedge clk or posedge reset) begin
if (reset) state <= S0;
else state = next_state;
end
always_comb begin
case(state)
S0: next_state = S1;
S1: next_state = S0;
default: next_state = S0;
endcase
endSolution
Step 1: Check assignments in always_ff block
In sequential blocks (always_ff), non-blocking assignment (<=) must be used to avoid race conditions.Step 2: Identify the incorrect assignment
The linestate = next_state;uses blocking assignment (=), which is incorrect here.Final Answer:
Using blocking assignment (=) instead of non-blocking (<=) in always_ff block -> Option BQuick Check:
always_ff requires <= for state updates [OK]
- Using = instead of <= in sequential blocks
- Forgetting reset condition
- Incorrect sensitivity list in always_comb
flag which is high only when the FSM is in state S2. Which block should you put the flag assignment in, and what is the correct style?Solution
Step 1: Identify where output signals are assigned in three-block FSM
Output signals based on current state are assigned in the output logic block, which is combinational and usesalways_comb.Step 2: Write the correct assignment for flag
Assignflag = (state == S2);inside the output logic block to reflect current state.Final Answer:
In the output logic block using always_comb, assign flag = (state == S2); -> Option DQuick Check:
Output logic uses always_comb with flag = (state == S2) [OK]
- Assigning outputs in always_ff block
- Using next_state instead of state for outputs
- Ignoring combinational output logic block
Ready to prove it?
Pass the test and this pattern moves unknown
