← Back to list

FSM Design 101: Building a Traffic Light Controller in Verilog

Every traffic light you have ever waited at is running a tiny program. It cycles through a fixed set of conditions — green, then yellow…

csjo logicion · 2026-06-14 00:18 · 1 claps · 3.9 min read
#fpga #verilog #digital-design #hardware #programming
Open on Medium ↗
Wiki topics: 💻 · Programming 🏃 · Running & Endurance

FSM Design 101: Building a Traffic Light Controller in Verilog

Every traffic light you have ever waited at is running a tiny program. It cycles through a fixed set of conditions — green, then yellow, then red — and it never skips or repeats out of order. That predictable, step-by-step behavior is exactly what engineers call a finite state machine, or FSM. If you are learning Verilog, the traffic light controller is the perfect first FSM to build: it is simple enough to reason about on paper, yet it teaches the same pattern you will use for everything from UART receivers to memory controllers.

In this guide we will start from the idea of a state machine, draw the states for a traffic light, and then translate that drawing into clean, synthesizable Verilog. By the end you will have a template you can reuse for almost any sequential design.

What Is a Finite State Machine?

A finite state machine is a design that can be in exactly one of a small, fixed number of states at any moment. It moves from one state to the next based on rules, and on every clock tick it decides where to go. Three ideas define any FSM: the set of states, the transitions that move between them, and the outputs produced in each state.

There are two flavors you will hear about. In a Moore machine, the outputs depend only on the current state. In a Mealy machine, the outputs depend on the current state and the inputs. Moore machines are easier for beginners to reason about because the output is glitch-free and tied directly to the state, so we will build our traffic light as a Moore machine.

Mapping Out the Traffic Light States

Our controller is intentionally simple: it walks through three states in a loop, holding each one for a number of clock cycles before advancing. The states and their light outputs are:

State    Red  Yellow  Green   Meaning
S_GREEN   0     0       1     Traffic flows
S_YELLOW  0     1       0     Prepare to stop
S_RED     1     0       0     Stop

Transitions (one-way loop):
   S_GREEN --> S_YELLOW --> S_RED --> S_GREEN

Notice that because this is a Moore machine, each row of the table shows outputs that depend only on the state — not on any external input. Real intersections add inputs like pedestrian buttons or sensors, but the three-state loop is the backbone you build on top of.

Writing the FSM in Verilog

The cleanest way to write an FSM is the three-block style: one block for the state register, one for the next-state logic, and one for the outputs. Separating these makes the code easy to read and helps the synthesis tool do the right thing. Here is the full controller, including a simple counter so each light stays on for a fixed number of clock cycles.

module traffic_light (
    input  wire clk,
    input  wire rst_n,      // active-low reset
    output reg  red,
    output reg  yellow,
    output reg  green
);

    // State encoding
    localparam S_GREEN  = 2'd0,
               S_YELLOW = 2'd1,
               S_RED    = 2'd2;

    // How long each light stays on, in clock cycles
    localparam GREEN_TIME  = 10,
               YELLOW_TIME = 3,
               RED_TIME    = 10;

    reg [1:0]  state, next_state;
    reg [31:0] counter;

    // Block 1: state register and timer
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state   <= S_GREEN;
            counter <= GREEN_TIME - 1;
        end else if (counter == 0) begin
            state   <= next_state;
            counter <= (next_state == S_YELLOW) ? YELLOW_TIME - 1 :
                       (next_state == S_RED)    ? RED_TIME    - 1 :
                                                  GREEN_TIME  - 1;
        end else begin
            counter <= counter - 1;
        end
    end

    // Block 2: next-state logic
    always @(*) begin
        case (state)
            S_GREEN : next_state = S_YELLOW;
            S_YELLOW: next_state = S_RED;
            S_RED   : next_state = S_GREEN;
            default : next_state = S_GREEN;
        endcase
    end

    // Block 3: output logic (Moore)
    always @(*) begin
        red = 1'b0; yellow = 1'b0; green = 1'b0;
        case (state)
            S_GREEN : green  = 1'b1;
            S_YELLOW: yellow = 1'b1;
            S_RED   : red    = 1'b1;
        endcase
    end

endmodule

Walk through it slowly. Block 1 is the only part with a clock edge, so it is the only sequential logic. It resets into the green state and reloads the counter every time a state finishes, counting down one cycle at a time. Block 2 is pure combinational logic that answers a single question: given the current state, what comes next? Block 3 sets all three lights to zero and then turns on exactly one, guaranteeing the outputs always match the state.

Moore vs Mealy at a Glance

We chose a Moore machine, but it helps to know how the two styles compare so you can pick the right one next time:

                    Moore machine            Mealy machine
Output depends on   Current state only       State + inputs
Timing              Outputs change on clock  Outputs can change anytime
Glitches            Less prone               More prone
States needed       Sometimes more           Often fewer
Best for beginners  Yes                      Later, once comfortable

Common Beginner Mistakes

Three traps catch almost everyone writing their first FSM. The first is forgetting the default case in the next-state logic, which can create an unintended latch and leave your machine stuck if it ever lands in an unused state. The second is mixing blocking and non-blocking assignments: use non-blocking (the arrow operator) in clocked blocks and blocking (the equals sign) in combinational blocks. The third is driving the same output from two different always blocks, which causes a multiple-driver error. Keeping the three-block structure clean is the easiest way to avoid all three.

What’s Next

You now have a working FSM, but how do you know it actually behaves correctly before loading it onto hardware? That is where verification comes in. In the next article, “What is Hardware Verification and Why Does It Matter?”, we will look at why engineers spend more time checking designs than writing them, and how a good testbench catches bugs your eyes never will. Try extending today’s controller first: add a pedestrian-crossing state, or a fourth all-red safety phase, and see how the state diagram grows.

If this helped FSMs finally click for you, follow for more FPGA content. New beginner-friendly Verilog and FPGA guides go out regularly.


메타데이터
post_id
28121755af79
slug
fsm-design-101-building-a-traffic-light-controller-in-verilog-28121755af79
url
https://medium.com/@ahe24mobile/fsm-design-101-building-a-traffic-light-controller-in-verilog-28121755af79
canonical_url
https://medium.com/@ahe24mobile/fsm-design-101-building-a-traffic-light-controller-in-verilog-28121755af79
author_url
https://medium.com/@ahe24mobile
status
ok
fetched_at
2026-06-17 08:20:12