What an FSM Is
A finite state machine is a controller that:
- Holds one of a fixed set of named states at any given time.
- Transitions between states based on inputs (and possibly the current state).
- Produces outputs that depend on the current state (and maybe the current inputs).
That covers a startling amount of digital design: traffic-light controllers, UART transmitters, memory controllers, network protocol handlers, instruction decoders, anything that has discrete operating modes.
The thing that makes FSMs feel different from datapath logic is that they're states, not values. A counter ticks through 1, 2, 3, 4. An FSM ticks through IDLE, FETCHING, BUSY, DONE - same shape, but the states have names and the transitions have meaning.
The Two-Process Pattern
The standard Verilog FSM uses two always blocks:
- A clocked block that captures the state register on each clock edge. Uses non-blocking assignment. Tiny - usually three lines.
- A combinational block that uses a
caseon the current state to compute the next state and the outputs. Uses blocking assignment. The "interesting" code lives here.
This separation has three benefits: it forces you to think about state explicitly, it produces hardware that maps cleanly to "one register plus one combinational block", and it's the standard - everybody who reads your Verilog will recognize it instantly.
A Worked Example: Sequence Detector
A classic teaching FSM: detect the bit sequence 1011 on a serial input. Output a single-cycle pulse when the sequence completes.
The two-block structure is the bullet point above. The cleaning details are worth pointing out:
- Defaults at the top of the combinational block.
next_state = state(stay where you are) anddetected = 1'b0(no pulse) are the "do nothing" assignments. Everycasebranch then only sets the things that differ. This makes it impossible to infer a latch. localparamfor state names. Anyone reading the module thinks inS0,S1,S2,S3, not in3'd0,3'd1. The synthesizer makes the substitution.- No outputs from the clocked block. All the "what does this state do" logic lives in the combinational block. The clocked block is responsible for nothing except holding the current state.
Moore vs Mealy
Moore: output depends only on the current state. Mealy: output depends on the current state and the current inputs.
In the example above, detected is set inside the S3 branch only when in matches one of the expected sequence-completing patterns. That's a Mealy output - it depends on in in addition to state. A Moore version would have a separate state for "just detected" and set detected = 1 whenever that state is current; the output would pulse a cycle later but never be sensitive to a glitch on in.
Both styles are valid. Moore is the default in textbooks because outputs are guaranteed not to glitch when inputs change mid-cycle. Mealy is faster (no register latency for input-driven outputs) and produces smaller hardware in many cases. Pick based on the protocol you're implementing.
State Encoding: Binary, One-Hot, Gray
The bit pattern you assign to each state matters for area and speed:
- Binary (
S0 = 3'd0,S1 = 3'd1, ...): smallest state register - bits for states. Maximum decode logic. - One-hot (
S0 = 4'b0001,S1 = 4'b0010, ...): N bits for N states. Decode logic is trivial (each state is one wire); transitions are fast. FPGAs often default to this. - Gray code: consecutive states differ by one bit. Useful when state bits cross clock domains.
Most modern synthesis tools pick the encoding for you (Vivado, Quartus, Design Compiler all have an automatic mode that tries each and picks the best). You rarely need to specify. Specify when you do: most tools accept an attribute annotation or a (* fsm_encoding = "one_hot" *) pragma.
A Three-Block Variant
You'll occasionally see the FSM split three ways: one clocked block for state, one combinational block for next-state, one combinational block for outputs. That's just the two-block pattern with the output-computation hoisted out into its own block:
// State register
always @(posedge clk) ...
// Next-state logic
always @(*) ...
// Output logic
always @(*) begin
case (state)
...
endcase
end
The split-output style is useful when outputs are large and the next-state logic would be cluttered if they were in the same block. For small FSMs it's overkill.
What default Does in an FSM
Every FSM's case statement should have a default branch. Two reasons:
- Safety: if the state register somehow takes an invalid value (corruption, bug, partial reset),
defaultbrings it back to a known state. - Synthesis hint: when the explicit cases are exhaustive (a 2-bit state with all 4 values handled, for instance),
default: next_state = 'x;tells the synthesizer "I promise the default is unreachable, optimize freely". If the unreachable path does get hit in simulation, the resultingxpropagates and surfaces the bug immediately.
default: begin
next_state = S0; // safe recovery
// or
next_state = 'x; // unreachable, optimize freely
end
Pick based on whether you've proven the default is truly unreachable.
Things to Watch For
Forgetting defaults at the top of the combinational block. Without next_state = state and the output defaults, a branch that doesn't assign everything leaks a latch.
Putting outputs in the clocked block. If detected <= 1 lives in the always @(posedge clk) block, the output is registered - it appears one cycle late. That can be intentional (a "registered Mealy" output), but it's a common accidental design mistake when the spec calls for an instant pulse.
Mixing blocking and non-blocking. Clocked block: <=. Combinational block: =. Mixing the two within one block is a race condition.
A combinational always block that references next_state and assigns state. That builds a feedback loop the simulator can't resolve. The clocked block owns state; the combinational block owns next_state; never let either touch the other's variable.
What Comes Next
You can now build any controller you can describe. The next chapter takes a step back from synthesizable design and covers the testbenches that exercise it - how to drive stimulus, observe outputs, dump waveforms, and validate that your modules actually do what you think they do.
Frequently Asked Questions
What is a finite state machine in Verilog?
An FSM is a controller that holds one of a small set of named states and transitions between them based on inputs. In Verilog, the standard implementation has two blocks: a clocked always that updates the state register on each clock edge, and a combinational always that computes the next state and the outputs based on the current state and inputs.
What is the standard FSM pattern in Verilog?
Two-process FSM: one clocked always @(posedge clk) block holds the state register and uses non-blocking assignment, and one combinational always @(*) block uses a case on the current state to compute next state and outputs. This separation makes the code easy to read, lint, and synthesize cleanly.
What is the difference between a Mealy and Moore FSM?
In a Moore FSM, outputs depend only on the current state. In a Mealy FSM, outputs depend on both the current state and the current inputs. Mealy machines react one cycle faster (no register latency for input-dependent outputs) but can produce glitches if inputs change mid-cycle. Moore machines are slower by one cycle but more predictable - they're the default choice unless you need the speed.
How do you encode states in Verilog?
Use localparam constants inside the module: localparam IDLE = 3'd0; etc. Three common encodings: binary (states 0, 1, 2, ... - smallest state register), one-hot (one bit per state, fewer logic levels per transition), and gray code (consecutive states differ by one bit - minimizes glitches). Synthesis tools usually pick the encoding for you; pinning it down is rarely necessary.