Discover how splitting your FSM code into three blocks can save hours of debugging frustration!
Why Three-block FSM coding style in Verilog? - Purpose & Use Cases
Imagine trying to design a digital circuit that changes states based on inputs, but you write all the logic in one big block. It quickly becomes a tangled mess where it's hard to track what controls state changes, outputs, or resets.
Writing the entire state machine in one block makes the code confusing and error-prone. It's easy to mix up state updates, output logic, and input handling, leading to bugs that are hard to find and fix.
The three-block FSM style splits the design into clear parts: one block for state transitions, one for output logic, and one for state registers. This separation makes the design easier to read, debug, and maintain.
always @(posedge clk) begin if (reset) state <= IDLE; else if (input) state <= NEXT_STATE; output = (state == SOME_STATE); end
always @(posedge clk) begin if (reset) state <= IDLE; else state <= next_state; end always @(*) begin case(state) IDLE: next_state = input ? SOME_STATE : IDLE; default: next_state = IDLE; endcase end always @(*) begin output = (state == SOME_STATE); end
This style lets you build reliable, clear, and scalable state machines that are easy to understand and modify.
When designing a traffic light controller, using three-block FSM style helps separate timing control, light output signals, and state changes, making the design straightforward and safe.
Manual FSM code can get messy and hard to debug.
Three-block FSM style separates state update, next state logic, and output logic.
This separation improves clarity, reduces bugs, and simplifies changes.
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
