FSMs are how digital hardware makes decisions over time. A traffic light, a UART protocol controller, a CPU's fetch-decode-execute cycle — all FSMs. Mastering the 3-always-block style in Verilog is one of the most valuable skills in FPGA/ASIC design. This lesson builds a traffic light FSM from state diagram to tested Verilog.
| Moore FSM | Mealy FSM | |
|---|---|---|
| Output depends on | State only | State + current inputs |
| Output timing | Registered — glitch-free | Combinational — faster but can glitch |
| Typical use | FPGA outputs, control signals | Tight-latency handshakes |
We build a Moore FSM — outputs are stable and registered, which makes timing analysis easy on FPGAs.
Block 1 (clocked) — state register: state <= next_state
Block 2 (combinational) — next-state logic: compute next_state from state + inputs
Block 3 (combinational) — output logic: compute outputs from state only (Moore)
// Traffic light Moore FSM
// tick input is a slow enable pulse (e.g. from clkdiv at 1 Hz)
module traffic_light (
input wire clk,
input wire rst,
input wire tick, // advance state once per tick
output reg red, // 1 = red light on
output reg amber, // 1 = amber light on
output reg green // 1 = green light on
);
// State encoding
localparam GREEN = 2'd0, AMBER = 2'd1, RED = 2'd2, AMB2 = 2'd3;
reg [1:0] state, next_state;
// Block 1: state register
always @(posedge clk) begin
if (rst) state <= GREEN;
else state <= next_state;
end
// Block 2: next-state logic (combinational)
always @(*) begin
next_state = state; // default: hold
if (tick) begin
case (state)
GREEN: next_state = AMBER;
AMBER: next_state = RED;
RED: next_state = AMB2;
AMB2: next_state = GREEN;
default: next_state = GREEN;
endcase
end
end
// Block 3: output logic (Moore — state only)
always @(*) begin
{red, amber, green} = 3'b000; // default off
case (state)
GREEN: green = 1'b1;
AMBER: amber = 1'b1;
RED: red = 1'b1;
AMB2: {red, amber} = 2'b11;
endcase
end
endmodule`timescale 1ns/1ps
module tb_traffic_light;
reg clk=0,rst=1,tick=0;
wire red,amber,green;
traffic_light dut(.clk(clk),.rst(rst),.tick(tick),.red(red),.amber(amber),.green(green));
always #5 clk=~clk;
integer errors=0;
task chk(input er,ea,eg);
if({red,amber,green}!={er,ea,eg})begin $display("FAIL r=%b a=%b g=%b exp=%b%b%b",red,amber,green,er,ea,eg);errors=errors+1;end
else $display("ok r=%b a=%b g=%b",red,amber,green);
endtask
task do_tick; tick=1;@(posedge clk);#1;tick=0;endtask
initial begin
@(posedge clk);rst=0;@(posedge clk);#1;
chk(0,0,1); // GREEN
do_tick; chk(0,1,0); // AMBER
do_tick; chk(1,0,0); // RED
do_tick; chk(1,1,0); // AMB2
do_tick; chk(0,0,1); // back to GREEN
if(errors==0) $display("ALL TESTS PASSED"); else $display("%0d FAILED",errors);
$finish;
end
endmoduleok r=0 a=0 g=1 ok r=0 a=1 g=0 ok r=1 a=0 g=0 ok r=1 a=1 g=0 ok r=0 a=0 g=1 ALL TESTS PASSED
A design pattern where a system is always in one of a finite set of states, transitioning based on inputs and producing outputs per state (Moore) or state+input (Mealy).
Moore: outputs = f(state) only — registered and glitch-free. Mealy: outputs = f(state, inputs) — faster response but can glitch.
Separates state register (clocked), next-state logic (combinational), and output logic (combinational). Cleaner, easier to synthesize and debug.