0
0
Verilogprogramming~15 mins

Three-block FSM coding style in Verilog - Deep Dive

Choose your learning style9 modes available
Overview - Three-block FSM coding style
What is it?
The three-block FSM coding style is a way to write finite state machines in Verilog using three separate always blocks. Each block has a clear job: one for state transitions, one for output logic, and one for updating the current state. This style helps organize the code and makes it easier to understand and maintain.
Why it matters
Without a clear structure, FSM code can become confusing and error-prone, making debugging hard and increasing the chance of mistakes. The three-block style solves this by separating concerns, so each part of the FSM is simple and focused. This leads to more reliable hardware designs and easier teamwork.
Where it fits
Before learning this, you should understand basic Verilog syntax and what a finite state machine is. After mastering this style, you can explore more complex FSM designs, optimization techniques, and formal verification methods.
Mental Model
Core Idea
Separate the FSM into three clear parts: deciding the next state, producing outputs, and updating the current state, each in its own code block.
Think of it like...
It's like a traffic light controller where one person decides the next light color based on rules, another person shows the light color to drivers, and a third person remembers the current light color to use next time.
┌───────────────┐   next_state   ┌───────────────┐
│ Current State │──────────────▶│ Next State    │
└───────────────┘               └───────────────┘
       │                              │
       │                              ▼
       │                      ┌───────────────┐
       │                      │ Output Logic  │
       │                      └───────────────┘
       │                              │
       ▼                              ▼
┌───────────────┐               ┌───────────────┐
│ State Update  │◀──────────────│ Clock/Reset   │
└───────────────┘               └───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding FSM basics
🤔
Concept: Learn what a finite state machine is and its parts: states, transitions, and outputs.
A finite state machine (FSM) is a system that can be in one state at a time. It changes states based on inputs and produces outputs depending on the current state. For example, a simple door lock can be locked or unlocked, changing state when a correct code is entered.
Result
You understand the basic idea of states and transitions in a system.
Knowing what FSMs do helps you see why organizing their code clearly is important.
2
FoundationBasic Verilog FSM structure
🤔
Concept: Learn how to write a simple FSM in Verilog using one always block.
In Verilog, you can write an FSM by combining state updates and outputs in one always block triggered by the clock. For example: always @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end This mixes state update and next state logic.
Result
You can write a simple FSM but the code may get messy as complexity grows.
Seeing the limits of one-block FSMs motivates the need for clearer styles.
3
IntermediateSeparating next state logic
🤔Before reading on: do you think next state logic should be inside the clocked block or separate? Commit to your answer.
Concept: Move the logic that decides the next state into its own always block triggered by inputs and current state.
Instead of mixing next state calculation with state updates, write a combinational always block: always @(*) 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 This block only decides next_state based on current inputs and state.
Result
Next state logic is cleanly separated and easier to read.
Separating next state logic prevents unintended latches and makes FSM behavior clearer.
4
IntermediateAdding output logic block
🤔Before reading on: should output logic depend only on current state or also on next state? Commit to your answer.
Concept: Create a separate combinational block for outputs, based on the current state (Moore FSM) or current state and inputs (Mealy FSM).
For a Moore FSM, outputs depend only on the current state: always @(*) begin case (state) IDLE: out = 0; RUN: out = 1; default: out = 0; endcase end This keeps output logic separate from state transitions.
Result
Output signals are clearly defined and easy to modify.
Separating output logic helps avoid bugs where outputs change unexpectedly.
5
IntermediateClocked state update block
🤔
Concept: Use a clocked always block to update the current state from the next state on each clock cycle.
This block updates the state register: always @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end It only handles state storage, not logic.
Result
State updates happen synchronously and predictably.
Separating state update ensures timing is controlled and clear.
6
AdvancedHandling asynchronous reset cleanly
🤔Before reading on: does asynchronous reset belong in the next state or state update block? Commit to your answer.
Concept: Implement asynchronous reset only in the clocked state update block to avoid glitches.
The reset signal is handled in the state update block: always @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end Next state and output blocks do not handle reset directly.
Result
Reset works reliably without causing combinational glitches.
Knowing where to place reset avoids subtle timing bugs in FSMs.
7
ExpertAvoiding common FSM coding pitfalls
🤔Before reading on: do you think mixing blocking and non-blocking assignments in FSM blocks is safe? Commit to your answer.
Concept: Use non-blocking assignments in clocked blocks and blocking assignments in combinational blocks to prevent simulation mismatches and race conditions.
In the clocked block: always @(posedge clk or posedge reset) begin if (reset) state <= IDLE; // non-blocking else state <= next_state; end In combinational blocks: always @(*) begin case (state) IDLE: next_state = RUN; // blocking ... endcase end Mixing these incorrectly can cause simulation vs hardware mismatches.
Result
FSM behaves correctly in simulation and hardware.
Understanding assignment types prevents the most common FSM bugs in real projects.
Under the Hood
The three-block FSM style works by splitting the FSM into combinational and sequential logic. The next state and output blocks are combinational, meaning they react immediately to input changes and current state. The state update block is sequential, triggered by the clock and reset signals, storing the current state in flip-flops. This separation matches how hardware circuits are built, making the design predictable and synthesizable.
Why designed this way?
This style was created to improve readability, maintainability, and correctness of FSMs in hardware design. Early FSMs mixed all logic in one block, causing confusion and bugs. Separating concerns aligns with hardware principles and helps tools optimize the design. Alternatives like one-block FSMs are simpler but less scalable and error-prone.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Current State │──────▶│ Next State    │──────▶│ State Update  │
│ (register)    │       │ Logic (comb.) │       │ (clocked reg) │
└───────────────┘       └───────────────┘       └───────────────┘
        │                      │                       │
        │                      ▼                       │
        │               ┌───────────────┐             │
        └──────────────▶│ Output Logic  │◀────────────┘
                        │ (comb.)      │
                        └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Is it okay to mix blocking and non-blocking assignments freely in FSM code? Commit to yes or no.
Common Belief:You can use blocking or non-blocking assignments anywhere in FSM code without issues.
Tap to reveal reality
Reality:Clocked blocks must use non-blocking assignments to avoid race conditions; combinational blocks should use blocking assignments for correct simulation.
Why it matters:Mixing assignment types incorrectly causes simulation mismatches and hardware bugs that are hard to debug.
Quick: Does output logic always depend only on the current state? Commit to yes or no.
Common Belief:Outputs in FSMs always depend only on the current state (Moore style).
Tap to reveal reality
Reality:Outputs can depend on current state and inputs (Mealy style), which can make outputs change faster but also more complex.
Why it matters:Assuming Moore outputs only can limit design flexibility and cause incorrect output timing assumptions.
Quick: Should asynchronous reset be handled in combinational blocks? Commit to yes or no.
Common Belief:Reset signals can be handled anywhere in FSM code, including combinational blocks.
Tap to reveal reality
Reality:Asynchronous reset must be handled only in the clocked state update block to avoid glitches and synthesis issues.
Why it matters:Incorrect reset handling can cause unpredictable FSM behavior and hardware faults.
Quick: Is one always-block FSM style better for small designs? Commit to yes or no.
Common Belief:Using one always block for FSMs is simpler and better for small designs.
Tap to reveal reality
Reality:Even small FSMs benefit from three-block style for clarity and fewer bugs.
Why it matters:Ignoring this leads to bad habits that cause bigger problems as designs grow.
Expert Zone
1
The choice between Moore and Mealy output styles affects timing and complexity; experts carefully pick based on latency and glitch tolerance.
2
Using parameters or enums for state encoding improves readability and allows synthesis tools to optimize state registers.
3
Careful sensitivity list management in combinational blocks prevents unintended latches and simulation mismatches.
When NOT to use
Avoid three-block FSM style when designing ultra-simple FSMs with only two states and trivial outputs; a single always block may suffice. For highly optimized or timing-critical designs, consider one-hot or encoded FSM styles with specialized tools.
Production Patterns
In real projects, three-block FSMs are combined with parameterized state definitions, reset synchronization, and formal verification assertions. Teams use this style to ensure code reviews catch logic errors early and to support automated testbench generation.
Connections
State Machine Theory
Builds-on
Understanding the theoretical model of states and transitions helps grasp why FSMs are structured with clear state and output logic.
Software Design Patterns
Similar pattern
The separation of concerns in three-block FSMs mirrors software patterns like Model-View-Controller, improving modularity and maintainability.
Digital Circuit Timing
Depends on
Knowing how clock edges and resets work in hardware clarifies why FSM updates must be synchronous and outputs combinational.
Common Pitfalls
#1Mixing blocking and non-blocking assignments in the same always block.
Wrong approach:always @(posedge clk) begin state = next_state; // blocking assignment end
Correct approach:always @(posedge clk) begin state <= next_state; // non-blocking assignment end
Root cause:Confusing assignment types leads to simulation and hardware mismatches.
#2Forgetting to include all inputs in the sensitivity list of combinational blocks.
Wrong approach:always @(state) begin // missing inputs in sensitivity list if (input_signal) next_state = RUN; end
Correct approach:always @(*) begin if (input_signal) next_state = RUN; end
Root cause:Incomplete sensitivity lists cause simulation mismatches and unintended latches.
#3Handling asynchronous reset in combinational blocks.
Wrong approach:always @(*) begin if (reset) next_state = IDLE; else ... end
Correct approach:always @(posedge clk or posedge reset) begin if (reset) state <= IDLE; else state <= next_state; end
Root cause:Reset must be synchronous or asynchronous only in clocked blocks to avoid glitches.
Key Takeaways
The three-block FSM style divides the FSM into next state logic, output logic, and state update blocks for clarity and correctness.
Separating combinational and sequential logic matches hardware design principles and prevents common bugs.
Using non-blocking assignments in clocked blocks and blocking assignments in combinational blocks is essential for correct simulation and synthesis.
Proper handling of asynchronous reset only in the clocked state update block avoids glitches and unpredictable behavior.
This style improves maintainability and scalability of FSM designs, making it the preferred approach in professional hardware development.