Project 11: Traffic Light Controller
Build a timed FSM that cycles through green, yellow, red safely.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Intermediate |
| Time Estimate | 1 weekend |
| Main Programming Language | Verilog (Alternatives: VHDL, SystemVerilog) |
| Alternative Programming Languages | VHDL, SystemVerilog |
| Coolness Level | Medium |
| Business Potential | Low |
| Prerequisites | FSMs, Counters |
| Key Topics | FSM, Timing, Output decoding |
1. Learning Objectives
- Design a state diagram
- Implement timed transitions
- Map states to outputs
2. All Theory Needed (Per-Concept Breakdown)
Finite State Machine Design
Description/Expanded Explanation of the concept
FSMs model systems that move between discrete states. They are the backbone of controllers: traffic lights, vending machines, UARTs, and CPUs. A clear state diagram and correct next-state logic are essential.
Definitions & Key Terms
- State -> encoded system condition
- Moore FSM -> outputs depend only on state
- Mealy FSM -> outputs depend on state and inputs
Mental Model Diagram (ASCII)
S0 --in--> S1 --in--> S2
^ |
+-----------------+

How It Works (Step-by-Step)
- Define states and transitions.
- Encode the states.
- Implement next-state combinational logic.
- Register the state on the clock edge.
Minimal Concrete Example
always @(posedge clk) begin
if (reset) state <= IDLE;
else state <= next_state;
end
Common Misconceptions
- “State encoding doesn’t matter.” -> It affects area and speed.
- “Mealy is always faster.” -> It can glitch if inputs change.
Check-Your-Understanding Questions
- When would you choose Moore over Mealy?
- How do you avoid glitches on outputs?
- How do you handle illegal states?
Where You’ll Apply It
- This project: used in Section 3.2 and Section 4
- Also used in: P11-traffic-light-controller.md, P13-serial-pattern-detector-finding-10110-in-a-bitstre.md, Final CPU
Counters and Clock Enables
Description/Expanded Explanation of the concept
Counters are registers that increment or decrement each clock cycle. Clock enables allow you to update a register only when needed, which is safer than gating clocks. They are essential for timing, PWM, and pacing visible outputs.
Definitions & Key Terms
- Counter -> register that increments/decrements
- Clock enable -> condition that allows a register update
- Prescaler -> counter used to slow down a signal
Mental Model Diagram (ASCII)
clk -> [counter] --tick--> [slow logic]

How It Works (Step-by-Step)
- Increment counter each clock edge.
- When counter reaches a limit, assert a tick.
- Use tick as a clock enable for slower logic.
Minimal Concrete Example
if (tick) out <= out + 1;
Common Misconceptions
- “Gating the clock is simpler.” -> It can break timing and glitch.
- “Counters are always free.” -> Wide counters consume resources.
Check-Your-Understanding Questions
- Why use clock enables instead of gating clocks?
- How do you choose counter width for a target frequency?
- What happens when a counter overflows?
Where You’ll Apply It
- This project: used in Section 3.2 and Section 5
- Also used in: P08-shift-register-led-chaser.md, P10-pwm-generator-led-dimmer-servo-control.md
Verification with Testbenches and Waveforms
Description/Expanded Explanation of the concept
Testbenches are simulation-only modules that apply stimulus and check outputs. Waveforms (VCD) are the hardware engineer’s microscope; they reveal timing, glitches, and ordering problems. A good testbench is deterministic and covers edge cases.
Definitions & Key Terms
- Testbench -> a non-synthesizable module that drives a DUT
- VCD -> Value Change Dump waveform file
- Deterministic test -> same inputs produce same outputs every run
Mental Model Diagram (ASCII)
[Testbench] -> [DUT] -> [VCD] -> [GTKWave]

How It Works (Step-by-Step)
- Initialize inputs to known values.
- Apply stimulus over time.
- Dump waveforms and check outputs.
- Add assertions or PASS/FAIL messages.
Minimal Concrete Example
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, tb);
a = 0; b = 1; #10;
$finish;
end
Common Misconceptions
- “If it simulates once, it’s correct.” -> Cover all relevant cases.
- “Waveforms are optional.” -> They are often the only way to debug timing.
Check-Your-Understanding Questions
- Why keep testbench and DUT separate?
- What is the purpose of
$dumpvars? - How do you make a testbench deterministic?
Where You’ll Apply It
- This project: used throughout Section 6 (testing)
- Also used in: all other projects in this folder
3. Project Specification
3.1 What You Will Build
A traffic light FSM with green/yellow/red phases and timers.
3.2 Functional Requirements
- Requirement 1: Cycle through states in correct order
- Requirement 2: Hold each state for configured duration
- Requirement 3: Output correct LED pattern
3.3 Non-Functional Requirements
- Performance: Stable operation at the target clock and interfaces.
- Reliability: Deterministic outputs on all defined inputs.
- Usability: Clear ports and documented behavior.
3.4 Example Usage / Output
{p['example_usage']}
3.5 Data Formats / Schemas / Protocols
{p[‘data_format’]}
3.6 Edge Cases
- Reset mid-cycle
- Timer overflow
3.7 Real World Outcome
3.7.1 How to Run (Copy/Paste)
vvp traffic_tb
3.7.2 Golden Path Demo (Deterministic)
Run the demo command above with the provided testbench and confirm the outputs match the golden transcript.
3.7.3 CLI Transcript
STATE=GREEN t=0..29
STATE=YELLOW t=30..34
STATE=RED t=35..64
3.7.4 Failure Demo (Expected)
# Example failure case
ERROR: Output mismatch at vector 3
Expected: 0x0A, Got: 0x0B
EXIT CODE: 1
Notes:
- Exit code 0 indicates all tests passed
- Exit code 1 indicates a test failure
4. Solution Architecture
4.1 High-Level Design
[inputs] -> [core logic] -> [outputs]

4.2 Key Components
| Component | Responsibility |
|---|---|
| fsm | State register and next-state logic |
| timer | Duration counter |
4.3 Data Structures (No Full Code)
// Example signals (adapt to your design)
reg [7:0] state_reg;
reg [7:0] data_reg;
4.4 Algorithm Overview
Key Algorithm: Core control flow
- Initialize state/reset conditions.
- Apply inputs and compute outputs.
- Update state on clock edges (if sequential).
Complexity Analysis:
- Time: O(1) per cycle
- Space: O(N) for registers and logic
5. Implementation Guide
5.1 Development Environment Setup
iverilog -v
# Ensure GTKWave is installed for waveform viewing
5.2 Project Structure
project-root/
|-- src/
| |-- top.v
| |-- core.v
|-- tb/
| |-- tb.v
|-- Makefile
|-- README.md

5.3 The Core Question You’re Answering
“How do you model timed real-world behavior with FSMs?”
5.4 Concepts You Must Understand First
- FSMs
- Counters
5.5 Questions to Guide Your Design
- Should timers be programmable?
- Moore or Mealy outputs?
5.6 Thinking Exercise
Draw a state diagram and label durations.
5.7 The Interview Questions They’ll Ask
- Moore vs Mealy: which is safer for outputs?
- How do you implement timed transitions?
5.8 Hints in Layers
- Use a timer counter per state.
- Reset timer on state change.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| FSMs | Digital Design and Computer Architecture | Ch. 3.4 |
5.10 Implementation Phases
Phase 1: Foundation
Goals:
- Establish core module structure
- Implement minimal behavior
Tasks:
- Scaffold module ports and internal signals
- Write a minimal testbench that compiles
Checkpoint: Simulation runs without errors
Phase 2: Core Functionality
Goals:
- Implement full logic
- Verify edge cases
Tasks:
- Complete core logic
- Add directed tests for edge cases
Checkpoint: All tests pass and waveforms match expectations
Phase 3: Polish & Edge Cases
Goals:
- Improve readability
- Document behavior
Tasks:
- Add comments and README notes
- Expand tests for unusual inputs
Checkpoint: Design is deterministic and documented
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Reset strategy | Sync / Async | Sync | Simpler timing closure |
| Test coverage | Directed / Exhaustive | Exhaustive for small logic | Prevents missed cases |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Unit Tests | Test core logic | Small vectors |
| Integration Tests | Test modules together | Full system |
| Edge Case Tests | Boundary conditions | Max/min values |
6.2 Critical Test Cases
- Test 1: Long simulation to confirm cycle order
- Test 2: Reset behavior mid-cycle
6.3 Test Data
Use deterministic vectors and document expected outputs.
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Skipped state | Timer not reset | Reset timer on transition |
7.2 Debugging Strategies
- Inspect waveforms at key internal signals
- Add temporary debug outputs to verify state
- Reduce testcases to the smallest failing case
7.3 Performance Traps
- Overly wide counters or combinational paths can reduce max clock
8. Extensions & Challenges
8.1 Beginner Extensions
- Add parameterization for widths
- Add optional features (enable, reset)
8.2 Intermediate Extensions
- Add configuration registers
- Build a simple driver or demo program
8.3 Advanced Extensions
- Integrate with another project in this series
- Implement a hardware demo on FPGA
9. Real-World Connections
9.1 Industry Applications
- Digital control systems and embedded peripherals
- FPGA prototyping and validation
9.2 Related Open Source Projects
- Yosys / nextpnr toolchain for open-source FPGA flow
- Example HDL projects in the FPGA community
9.3 Interview Relevance
- Demonstrates RTL thinking and verification skills
10. Resources
10.1 Essential Reading
- Digital Design and Computer Architecture - Focus on Ch. 3.4
10.2 Video Resources
- Search for project-specific HDL walkthroughs and waveforms
10.3 Tools & Documentation
- Icarus Verilog
- GTKWave
10.4 Related Projects in This Series
- See adjacent projects in
VERILOG_FROM_ZERO_PROJECTS/
11. Self-Assessment Checklist
11.1 Understanding
- I can explain the core concept without notes
- I can predict waveform behavior for basic inputs
11.2 Implementation
- All functional requirements are met
- All tests pass
- Edge cases are documented
11.3 Growth
- I can explain this project in an interview
- I documented at least one lesson learned
12. Submission / Completion Criteria
Minimum Viable Completion:
- Functional requirements implemented
- Testbench passes
- Waveforms inspected
Full Completion:
- All minimum criteria plus
- Edge cases covered and documented
Excellence (Going Above & Beyond):
- Hardware demo on FPGA
- Clear write-up of lessons learned
Appendix A: Deep Dive Walkthrough
A.1 Signal Map and State Outputs
- Inputs:
clk,reset - Outputs:
ns_red,ns_yellow,ns_green,ew_red,ew_yellow,ew_green
A.2 Suggested State Timing
- NS Green: 30 s
- NS Yellow: 5 s
- All Red: 2 s (safety)
- EW Green: 30 s
- EW Yellow: 5 s
- All Red: 2 s
A.3 State Diagram (Text)
NS_G -> NS_Y -> ALL_R -> EW_G -> EW_Y -> ALL_R -> NS_G

A.4 Deterministic Test Sequence
- Simulate with a faster clock (e.g., 1 kHz) and scaled timings.
- Verify each light combination persists for the exact programmed duration.
A.5 Debugging Tip
If two greens are on at once, check that your output logic is Moore-style (based only on state).
13. Deep Dive Appendix
13.1 Timing and Resource Budget
- Each light duration is a counter running for N seconds of system clock.
- Add an all-red safety interval to prevent overlaps.
- Make durations parameters so you can retime without editing FSM logic.
13.2 Waveform Interpretation Guide
- Verify each state holds for the correct number of cycles.
- Watch the state register and outputs together to confirm Moore behavior.
Example state order:
NS_green -> NS_yellow -> all_red -> EW_green -> EW_yellow -> all_red
13.3 Hardware Bring-Up Notes
- Drive 6 LEDs: NS (R/Y/G) and EW (R/Y/G).
- If using one LED bank, multiplex and label signals to avoid confusion.
- Slow the clock with a divider so transitions are visible.
13.4 Alternate Implementations and Trade-offs
- One-hot FSM: more flip-flops, simpler decode.
- Binary FSM: fewer flip-flops, more combinational decode.
- Time-encoded FSM: use a single timer plus state register.
13.5 Additional Exercises
- Add a pedestrian crossing state and pushbutton.
- Implement night mode flashing yellow.
- Add sensor input to extend green time when traffic is present.