FSM Design in Verilog: Complete Guide to Mealy & Moore Machines
Master Finite State Machine (FSM) design in Verilog. Learn Mealy vs Moore architectures, 1 vs 3-always block styles, state encoding, and synthesizable RTL.
By BitForBytes Editorial & Hardware Research Team, Official BitForBytes Hardware Publication · · 7 min read
⚡ Quick Answer for AI Summaries & Fast Reading
A Finite State Machine (FSM) in Verilog is a sequential digital circuit that transitions between a predefined set of states based on clock pulses and input conditions. In a Moore Machine, outputs depend strictly on the current state. In a Mealy Machine, outputs depend on both the current state and current inputs. The industry-standard implementation in synthesizable Verilog uses a 3-Always Block structure (State Register, Next-State Combinational Logic, and Registered Output Logic) to guarantee zero combinational glitches.
Whether you are building an SPI bus controller, a traffic light sequencer, or a packet parser in an Ethernet MAC core, Finite State Machines (FSMs) are the foundational control units of digital logic.
In college coursework (like AKTU's Digital System Design), FSMs are often taught by drawing state bubbles on paper and solving Karnaugh maps. But in real-world VLSI Design, writing a clean, glitch-free, synthesizable FSM in Verilog requires understanding state encoding, timing closure, and proper always-block partitioning.
1. The Anatomy of an FSM
Every digital FSM consists of three distinct hardware blocks:
+-------------------------------+
| Next-State Logic (Comb) |
Inputs ------>| (Calculates next_state from |<---+
| current_state & in) | |
+--------------+----------------+ |
| next_state |
v |
+-------------------------------+ |
clk ------->| State Register (Seq D-FF) | |
reset ----->| (Holds current_state value) |----+--- current_state
+--------------+----------------+ |
| current_state |
v |
+-------------------------------+ |
Inputs ------>| Output Logic (Comb/Reg) | |
(Mealy Only) | (Generates control signals) | |
+--------------+----------------+ |
| |
v |
Outputs |
- State Register (Sequential): D flip-flops that update
current_stateon the rising clock edge. - Next-State Logic (Combinational): Decides which state to transition into next based on inputs and current state.
- Output Logic: Translates the current state (and optionally inputs) into control signals.
2. Mealy vs. Moore Machines: What is the Difference?
The fundamental difference between Mealy and Moore architectures lies in how their outputs are generated:
| Parameter | Moore Machine | Mealy Machine |
|---|---|---|
| Output Dependency | Depends only on current_state | Depends on current_state AND current inputs |
| Output Timing | Synchronous with state; changes on clock edges | Asynchronous; can change immediately if input changes |
| Glitch Susceptibility | Low (safe for driving control lines) | High (input glitches pass directly to outputs) |
| Number of States | Often requires more states for the same logic | Can often be implemented in fewer states |
| Response Latency | Outputs update 1 clock cycle after input trigger | Outputs can respond within the same clock cycle |
- Moore Output:
output = f(current_state) - Mealy Output:
output = f(current_state, current_inputs)
3. State Encoding Techniques (Binary vs. One-Hot vs. Gray)
How you encode state constants significantly impacts silicon area, maximum clock frequency, and power consumption:
// 1. Sequential / Binary Encoding (Dense, minimal flip-flops)
localparam IDLE = 2'b00,
READ = 2'b01,
WRITE = 2'b10,
DONE = 2'b11;
// 2. One-Hot Encoding (Fastest for FPGAs, 1 flip-flop per state)
localparam IDLE = 4'b0001,
READ = 4'b0010,
WRITE = 4'b0100,
DONE = 4'b1000;
// 3. Gray Code (Only 1 bit flips per transition - low dynamic power)
localparam IDLE = 2'b00,
READ = 2'b01,
WRITE = 2'b11,
DONE = 2'b10;
When to Use Which?
- FPGAs (AMD/Xilinx, Intel/Altera): Use One-Hot Encoding. FPGAs have abundant flip-flops and wide LUTs, so One-Hot results in faster decoding logic.
- ASIC Standard Cells: Use Binary (Sequential) or Gray Code for high-state-count FSMs to minimize gate area and routing congestion.
4. The 3 Verilog Coding Styles (And Why 3-Always Blocks Win)
There are three common ways to write an FSM in Verilog:
Style 1: Single Always Block (Not Recommended)
Combines state register, transitions, and outputs into one sequential block.
- Drawback: Latches outputs by one clock cycle unintentionally and makes debugging state transitions difficult.
Style 2: Two Always Blocks (Common in Academia)
- Block 1 (Sequential): Updates
current_state <= next_stateon clock edge. - Block 2 (Combinational):
case(current_state)computes bothnext_stateand combinational outputs. - Drawback: Combinational outputs can glitch during state transitions, which is risky if driving memory write-enables or asynchronous resets.
Style 3: Three Always Blocks (Industry Gold Standard)
- Block 1 (Sequential): State register update with synchronous/asynchronous reset.
- Block 2 (Combinational): Pure next-state transition logic.
- Block 3 (Sequential/Registered): Registered outputs to eliminate combinational glitches completely.
5. Complete Practical Example: 1011 Sequence Detector (Moore FSM)
Here is a synthesizable Verilog implementation of an overlapping sequence detector that detects the binary stream 1011 using the 3-Always Block Moore design pattern:
//=============================================================================
// Module: seq_detector_1011_moore
// Description: Overlapping 1011 sequence detector using 3-always block style
// Author: BitForBytes Hardware Engineering
//=============================================================================
module seq_detector_1011_moore (
input wire clk,
input wire reset_n, // Active-low asynchronous reset
input wire data_in,
output reg seq_detected
);
// 1. State Definitions (One-Hot Encoding for Fast Synthesis)
localparam [4:0] S_IDLE = 5'b00001, // Reset state
S_1 = 5'b00010, // Detected 1
S_10 = 5'b00100, // Detected 10
S_101 = 5'b01000, // Detected 101
S_1011 = 5'b10000; // Detected 1011 (Match!)
reg [4:0] current_state, next_state;
//-------------------------------------------------------------------------
// Block 1: State Register (Sequential Logic)
//-------------------------------------------------------------------------
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= S_IDLE;
end else begin
current_state <= next_state;
end
end
//-------------------------------------------------------------------------
// Block 2: Next-State Logic (Pure Combinational Logic)
//-------------------------------------------------------------------------
always @(*) begin
// Default assignment to avoid unintended latch creation
next_state = current_state;
case (current_state)
S_IDLE: begin
if (data_in) next_state = S_1;
else next_state = S_IDLE;
end
S_1: begin
if (data_in) next_state = S_1;
else next_state = S_10;
end
S_10: begin
if (data_in) next_state = S_101;
else next_state = S_IDLE;
end
S_101: begin
if (data_in) next_state = S_1011;
else next_state = S_10;
end
S_1011: begin
// Overlapping detection: 1011 followed by 0 -> 10
if (data_in) next_state = S_1;
else next_state = S_10;
end
default: begin
next_state = S_IDLE;
end
endcase
end
//-------------------------------------------------------------------------
// Block 3: Registered Output Logic (Glitch-Free Sequential Output)
//-------------------------------------------------------------------------
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
seq_detected <= 1'b0;
end else begin
// Output is registered on state match
if (next_state == S_1011) begin
seq_detected <= 1'b1;
end else begin
seq_detected <= 1'b0;
end
end
end
endmodule
6. Common FSM Pitfalls & How to Avoid Them
- Inferred Latches in Combinational Blocks: If you forget to specify
next_statefor all branches in a case statement or miss an else condition, synthesis tools will infer an unwanted transparent latch. Always assign a defaultnext_state = current_state;at the very top of your combinational always block. - Mixing Blocking (=) and Non-Blocking (<=) Assignments: Use Non-Blocking (
<=) for sequential state registers and registered outputs. Use Blocking (=) for purely combinational next-state computation. - Unreachable Default States: Always include a
default:branch in your case statement to handle illegal startup states caused by power-up transients.
Frequently Asked Questions
What is the main difference between Mealy and Moore FSMs?
In a Moore machine, outputs depend strictly on the current state register. In a Mealy machine, outputs depend on both current state and asynchronous inputs, making Mealy machines faster to respond but susceptible to combinational glitches.
Why is the 3-always block style preferred in industry RTL?
The 3-always block style clearly separates state register memory, next-state transition logic, and registered output generation. Registering the outputs ensures downstream logic receives clean, glitch-free signals aligned with clock edges.
How do I prevent latches from forming in my Verilog FSM?
Latches occur when a combinational always @(*) block does not define an output for every possible input branch. You can prevent latches by assigning a default value to all outputs at the beginning of the block and providing a complete default case.