A finite state machine (FSM) is a sequential circuit that is always in one of a fixed number of states. On each clock edge, it moves to a next state chosen by its current state and its inputs, and it produces outputs based on its state, and sometimes its inputs. In Verilog, an FSM is usually written as a clocked always block that holds the state register and a combinational always block that computes the next state.
12 min read | Intermediate Level
What You'll Learn
- The difference between Moore and Mealy FSMs, and between binary and one-hot state encoding
- Write an FSM with the two-block style: a state register and next-state logic
- Generate outputs combinationally or from registers, and what each style synthesizes into
- Avoid latches, lost states and reset problems in FSM code
Types of FSMs
FSMs are classified in two independent ways: by how their outputs are produced, and by how their states are encoded in flip-flops.
By output generation:
| Moore FSM | Mealy FSM | |
|---|---|---|
| Outputs depend on | Current state only | Current state and current inputs |
| Output timing | Changes only after a clock edge | Can change as soon as an input changes |
| Number of states | Often more | Often fewer for the same behavior |
| Glitch risk | Low, outputs follow the state register | Higher, input glitches can pass to outputs |
By state encoding:
| Encoding | Example for 4 states | Flip-flops for N states | Characteristics |
|---|---|---|---|
| Binary | 00, 01, 10, 11 | $clog2(N) | Fewest flip-flops; more logic to decode each state |
| One-hot | 0001, 0010, 0100, 1000 | N | One flip-flop per state; very simple next-state and output logic; fast |
| Gray | 00, 01, 11, 10 | $clog2(N) | One bit changes per transition when states advance in sequence |
One-hot encoding is the same idea as a ring counter: each state has its own flip-flop. It is popular on FPGAs, which have many flip-flops, while ASIC designs with many states often use binary encoding to save area. Synthesis tools can also re-encode an FSM automatically when they recognize the structure.
Verilog FSM Structure
An FSM can be written with one always block or with two. The two-block style is recommended because it separates the two kinds of hardware in an FSM:
- A clocked (sequential) block that holds the current state in a register
- A combinational block that computes the next state from the current state and the inputs
Outputs are produced either inside the combinational block or with separate assign statements, or from registers when glitch-free outputs are needed.
The states are given names with localparam, so the code reads IDLE instead of 2'b00, and the encoding can be changed in one place. See Verilog Parameters.
// State encoding: binary, 2 bits for 3 states
localparam IDLE = 2'b00,
STATE_1 = 2'b01,
STATE_2 = 2'b10;
reg [1:0] cur_state; // Output of the state register
reg [1:0] next_state; // Output of the next-state logic
Sequential Always Block
The state register changes only on the clock edge. On reset, the FSM goes back to IDLE; otherwise it loads the next state computed by the combinational block. This block uses only non-blocking assignments, which model the register correctly and avoid race conditions with other clocked blocks.
always @ (posedge clk) begin
// If reset is asserted, go back to IDLE state
if (! resetn) begin
cur_state <= IDLE;
// Else transition to the next state
end else begin
cur_state <= next_state;
end
end
Combinational Always Block
This block computes the next state. It uses always @(*), so it re-evaluates whenever the current state or any input changes, and it uses blocking assignments, as all combinational blocks should. It starts with a default assignment so that every path assigns next_state.
// Combinational always block for next state logic
always @(*) begin
// Default: stay in the current state unless a transition below applies
next_state = cur_state;
case (cur_state)
IDLE: begin
if (input_signal)
next_state = STATE_1; // Transition to STATE_1 on input_signal
end
STATE_1: begin
if (!input_signal)
next_state = STATE_2; // Transition to STATE_2 if input_signal is low
end
STATE_2: next_state = IDLE; // Transition back to IDLE
default: next_state = IDLE; // Recover from any unused encoding (2'b11)
endcase
end
The default next_state = cur_state means "stay here" for every case that does not name a transition. So the FSM waits in IDLE until input_signal goes high, and waits in STATE_1 until it goes low. The default item of the case handles 2'b11, the one encoding that is not a valid state, by returning to IDLE.
Quick Check
Q: If the first line of the combinational block were next_state = IDLE; instead of next_state = cur_state;, what would happen in STATE_1 while input_signal stays high?
Show Answer
The FSM would return to IDLE on the next clock edge. STATE_1 only assigns next_state when input_signal is low, so in every other case the default applies. With a default of IDLE, every state that should wait instead jumps back to IDLE.
Output Generation
There are three common ways to produce the FSM's outputs.
1. In the combinational block. Assign a default value to every output at the start of the block, then override it in the states or transitions that need it. Assigning outputs in the same case as the next state keeps all the behavior of a state in one place. When several outputs change together, the assignments can be grouped in a task.
always @(*) begin
next_state = cur_state;
output_signal = 1'b0; // Default output value: no latch can be inferred
case (cur_state)
IDLE: if (input_signal)
next_state = STATE_1;
STATE_1: if (!input_signal) begin
next_state = STATE_2;
output_signal = 1'b1; // Depends on state AND input: Mealy output
end
STATE_2: next_state = IDLE;
default: next_state = IDLE;
endcase
end
Here output_signal is 1 during the cycle in which the FSM is in STATE_1 and input_signal is low. Because it depends on an input, it is a Mealy output.
2. With continuous assignments. A Moore output can be written as a comparison on the current state. This is clear for a few outputs, but becomes repetitive when there are many states and outputs.
assign op_signal = (cur_state == STATE_1) ? 1 : 0;
3. From registers. Computing the output's next value combinationally and storing it in a flip-flop gives a glitch-free output that changes exactly on the clock edge, at the cost of one more flip-flop per output:
// Registered Moore output: high for exactly the cycles the FSM is in STATE_2
always @(posedge clk) begin
if (!resetn) done <= 1'b0;
else done <= (next_state == STATE_2);
end
Using next_state rather than cur_state makes done line up with the state: it goes high on the same edge on which the FSM enters STATE_2.
Where are FSMs Used?
A UART receiver is a classic FSM: it waits in an idle state for the falling edge of a start bit, moves to a state that samples the 8 data bits one per bit time, then checks the stop bit and returns to idle. Each state decides which counter runs and when the received byte is valid. Most protocol controllers, such as SPI, I2C and USB, are built the same way.
Complete Example
Putting the pieces together gives a full module. Its single Moore output, busy, is high whenever the FSM is not in IDLE.
module simple_fsm (
input clk,
input resetn, // Active-low synchronous reset
input input_signal,
output busy // Moore output
);
localparam IDLE = 2'b00,
STATE_1 = 2'b01,
STATE_2 = 2'b10;
reg [1:0] cur_state, next_state;
// 1. State register
always @(posedge clk) begin
if (!resetn) cur_state <= IDLE;
else cur_state <= next_state;
end
// 2. Next-state logic
always @(*) begin
next_state = cur_state;
case (cur_state)
IDLE : if (input_signal) next_state = STATE_1;
STATE_1 : if (!input_signal) next_state = STATE_2;
STATE_2 : next_state = IDLE;
default : next_state = IDLE;
endcase
end
// 3. Output logic
assign busy = (cur_state != IDLE);
endmodule
Synthesis result: The tool builds a 2-bit state register (two flip-flops with synchronous reset), a small block of combinational logic for the next state, made of the muxes and gates described by the case statement, and an OR gate for busy, which is 1 whenever either state bit is 1. Many synthesis tools recognize this structure as an FSM, report its states and transitions, and can choose a different encoding, such as one-hot, if it gives better timing.
Memory Controller Command Sequencing
DRAM devices must receive commands in a strict order with minimum delays between them: activate a row, wait, read or write, wait, then precharge before opening another row. The command scheduler in a memory controller is an FSM whose states represent these steps, combined with counters that enforce the required wait times in each state.
Elaborated Schematic
In the elaborated view, the current-state register appears as flip-flops, and the next-state logic appears as multiplexers selected by the current state and the inputs. The two-block coding style maps directly onto three parts of hardware:
- Present-state logic: the clocked block, which becomes the state register
- Next-state logic: the combinational block, which becomes muxes and gates
- Output logic: the output assignments, which become gates driven by the state register (and the inputs, for Mealy outputs)
Keeping these parts separate in the code makes the FSM easier to read, review and change. See Verilog Pattern Detector for a complete FSM example with a testbench.

Quick Check
Q: An FSM has 12 states. How many state flip-flops does it need with binary encoding, and with one-hot encoding?
Show Answer
Binary needs 4 ($clog2(12)), leaving 4 unused encodings. One-hot needs 12, one per state. One-hot uses three times as many flip-flops, but each state is identified by a single bit, so its next-state and output logic is smaller and faster.
Valid/Ready Handshakes
On-chip buses transfer data with a handshake: the sender raises valid and must hold its data until the receiver raises ready. The interface logic on each side is a small FSM with states such as "waiting to send" and "sending", and the transfer happens on the clock edge where both signals are high.
Common Beginner Mistakes
Mistake #1: No default assignment for next_state
Wrong: A combinational block where next_state is assigned only inside if conditions, with no default at the top
Right: Start the block with next_state = cur_state;
Why? In IDLE with input_signal low, no statement assigns next_state, so it must keep its old value and synthesis infers a latch. The same applies to every output assigned in the combinational block. See D Latch.
Mistake #2: Defaulting next_state to IDLE
Wrong: next_state = IDLE; as the first line of the combinational block
Right: next_state = cur_state;, and only use IDLE in the case default item
Why? It avoids the latch, but every state that should wait for a condition jumps back to IDLE instead. The FSM looks correct when the inputs change quickly in a testbench and fails when the real inputs stay high for several cycles.
Mistake #3: Mixing up blocking and non-blocking assignments
Wrong: cur_state = next_state; in the clocked block, or next_state <= ... in the combinational block
Right: Non-blocking (<=) in the clocked block, blocking (=) in the combinational block
Why? A blocking assignment in a clocked block can create race conditions with other clocked blocks that read the state. A non-blocking assignment in the combinational block means later statements in the same block see the old value, so defaults and overrides do not work as written. See Verilog Blocking & Non-Blocking.
Mistake #4: Forgetting the reset or the case default
Wrong: A state register with no reset, or a case with no default item when some encodings are unused
Right: Reset the state register to a defined state, and add default: next_state = IDLE;
Why? Without a reset, cur_state starts as x in simulation, matches no case item, and the FSM never starts. In hardware, it powers up in an unpredictable state. Without a default, an unused encoding reached through an upset has no way back to the valid states.
Practice Exercise
Challenge: Traffic Light Controller
Write a Moore FSM traffic_light with inputs clk, resetn and tick, and three outputs red, yellow and green. It has three states, RED, GREEN and YELLOW, in that order. The FSM moves to the next state only on a clock edge where tick is 1, and otherwise stays in its state. Reset goes to RED. Exactly one output is high in each state.
Hint
Use the same three parts as the complete example. In the combinational block, default next_state to cur_state and change it only when tick is 1. Since the outputs depend only on the state, write them with assign statements.
Solution
module traffic_light (
input clk,
input resetn, // Active-low synchronous reset
input tick, // Advance to the next light when 1
output red,
output yellow,
output green
);
localparam RED = 2'd0,
GREEN = 2'd1,
YELLOW = 2'd2;
reg [1:0] cur_state, next_state;
// State register
always @(posedge clk) begin
if (!resetn) cur_state <= RED;
else cur_state <= next_state;
end
// Next-state logic: advance only on tick
always @(*) begin
next_state = cur_state; // Hold by default
if (tick) begin
case (cur_state)
RED : next_state = GREEN;
GREEN : next_state = YELLOW;
YELLOW : next_state = RED;
default : next_state = RED;
endcase
end
end
// Moore outputs: depend only on the current state
assign red = (cur_state == RED);
assign green = (cur_state == GREEN);
assign yellow = (cur_state == YELLOW);
endmodule
In a real controller, tick would come from a timer, typically a Mod-N counter with a different count for each light. With one-hot encoding (3'b001, 3'b010, 3'b100), each output would simply be one bit of the state register, with no decoding logic at all.
Summary
In this tutorial, you learned:
- An FSM is always in one of a fixed set of states and moves between them on clock edges
- Moore outputs depend only on the state; Mealy outputs also depend on the inputs
- Binary encoding uses the fewest flip-flops; one-hot uses one per state and simplifies the logic
- The two-block style separates the state register (non-blocking) from the next-state logic (blocking)
- Default
next_statetocur_stateso states hold, and use thecasedefault to recover from unused encodings - Outputs can be combinational, from continuous assignments, or registered for glitch-free timing
- Synthesis builds a state register, next-state logic and output logic, and can re-encode the states