Building a Traffic Light Controller with open-source EDA tools โ Icarus Verilog, Yosys & OpenROAD on the Nangate45 PDK
In this post, we'll take a traffic light controller FSM from behavioral Verilog all the way through to a placed-and-routed silicon layout โ using only open-source tools. The design manages a highway/country-road intersection with sensor-triggered state transitions and counter-based timing delays.
A 5-state FSM with counter-based timing delays
| State | Highway | Country | Transition |
|---|---|---|---|
S0 |
GREEN | RED | When X=1 โ S1 |
S1 |
YELLOW | RED | After 3 clocks โ S2 |
S2 |
RED | RED | After 2 clocks โ S3 |
S3 |
RED | GREEN | When X=0 โ S4 |
S4 |
RED | YELLOW | After 3 clocks โ S0 |
module sig_control (
input wire clock, clear, X,
output reg [1:0] hwy, cntry
);
parameter RED=2'd0, YELLOW=2'd1, GREEN=2'd2;
parameter S0=3'd0, S1=3'd1, S2=3'd2, S3=3'd3, S4=3'd4;
parameter Y2RDELAY=3, R2GDELAY=2;
reg [2:0] state, next_state;
reg [2:0] count, next_count;
// Sequential: state + counter
always @(posedge clock) begin
if (clear) begin
state <= S0; count <= 3'd0;
end else begin
state <= next_state; count <= next_count;
end
end
// Combinational: next state with counter-based delays
always @(*) begin
next_state = state; next_count = 3'd0;
case (state)
S0: next_state = X ? S1 : S0;
S1: if (count==Y2RDELAY-1) next_state=S2;
else begin next_state=S1; next_count=count+1; end
S2: if (count==R2GDELAY-1) next_state=S3;
else begin next_state=S2; next_count=count+1; end
S3: next_state = X ? S3 : S4;
S4: if (count==Y2RDELAY-1) next_state=S0;
else begin next_state=S4; next_count=count+1; end
endcase
end
// Output logic decodes state โ light signals (omitted for brevity)
endmodule
repeat(@posedge clock) for delays โ this is simulation-only and cannot be
synthesized. We replaced it with a register-based counter that counts clock edges in
timed states (S1, S2, S4).
Compile & run with Icarus Verilog to confirm FSM behavior
# Compile RTL + testbench
$ iverilog -o t_sim t.v t_tb.v
# Run simulation
$ vvp t_sim
# View waveforms (optional)
$ gtkwave t.vcd
| File | Origin | Purpose |
|---|---|---|
t.v |
โ๏ธ Written | RTL design |
t_tb.v |
โ๏ธ Written | Testbench with stimulus & monitor |
t_sim |
๐ค Generated | Compiled simulation binary |
t.vcd |
๐ค Generated | Waveform dump for GTKWave |
Map behavioral Verilog to real Nangate45 standard cells
# 1. Read design
read_verilog t.v
# 2. Generic synthesis โ infer FSM, optimize
synth -top sig_control
# 3. Map flip-flops โ Nangate45 DFF cells
dfflibmap -liberty Nangate45_typ.lib
# 4. Map combinational logic โ Nangate45 gates
abc -liberty Nangate45_typ.lib
# 5. Cleanup, reports, output
opt_clean -purge
tee -o area_report.txt stat -liberty Nangate45_typ.lib
write_verilog t_synth.v
$ yosys -s yosys_run.tcl
Nangate45_typ.libThe Liberty (.lib) file is the heart of technology mapping. It defines every standard cell available in the Nangate45 PDK:
dfflibmap uses it to replace generic flip-flops with real DFF_X1 cells. abc
uses it to map all combinational logic to real gates.
| Cell | Count | Role |
|---|---|---|
DFF_X1 |
8 | D Flip-Flops (state + counter) |
INV_X1 |
7 | Inverters |
NAND2_X1 |
5 | 2-input NAND gates |
NOR3_X1 |
4 | 3-input NOR gates |
BUF_X1 |
3 | Buffers |
NAND3_X1 |
3 | 3-input NAND gates |
OAI22_X1 |
3 | OR-AND-Invert complex gates |
| + 7 more types | AOI, NOR, OR, XNOR gates | |
| File | Origin | Purpose |
|---|---|---|
t_synth.v |
๐ค Yosys | Gate-level netlist โ input to OpenROAD |
area_report.txt |
๐ค Yosys | Cell count & area breakdown |
timing_report.txt |
๐ค Yosys | Longest combinational path |
t_synth.dot |
๐ค Yosys | Circuit schematic (Graphviz format) |
Floorplan โ Place โ CTS โ Route โ Layout
# 10ns clock = 100 MHz
create_clock [get_ports clock] -name core_clock -period 10.0
# Input constraints: signals arrive 2ns after clock
set_input_delay 2.0 -clock core_clock [get_ports clear]
set_input_delay 2.0 -clock core_clock [get_ports X]
# Output constraints: signals must be ready 2ns before next edge
set_output_delay 2.0 -clock core_clock [get_ports {hwy[0]}]
set_output_delay 2.0 -clock core_clock [get_ports {hwy[1]}]
set_output_delay 2.0 -clock core_clock [get_ports {cntry[0]}]
set_output_delay 2.0 -clock core_clock [get_ports {cntry[1]}]
All sourced from OpenROAD/test/Nangate45/:
| File | Format | Contains |
|---|---|---|
Nangate45_typ.lib |
Liberty | Electrical: timing, power, capacitance per cell |
Nangate45_tech.lef |
Tech LEF | Metal layers: names, widths, spacing, vias |
Nangate45_stdcell.lef |
Cell LEF | Cell geometry: pin locations, cell dimensions |
Nangate45.tracks |
Tracks | Routing grid: pitch & offset per metal layer |
.lib. OpenROAD needs both.
$ openroad openroad_run.tcl
Timing met, zero DRC violations, 85% utilization
| Group | Internal | Switching | Leakage | Total | % |
|---|---|---|---|---|---|
| Sequential | 5.29 ยตW | 0.16 ยตW | 0.62 ยตW | 6.06 ยตW | 39.9% |
| Combinational | 0.56 ยตW | 0.51 ยตW | 0.84 ยตW | 1.91 ยตW | 12.6% |
| Clock | 5.00 ยตW | 1.95 ยตW | 0.26 ยตW | 7.21 ยตW | 47.5% |
| Total | 10.8 ยตW | 2.62 ยตW | 1.71 ยตW | 15.2 ยตW | 100% |
_78_/CK (DFF_X1) โ _78_/Q โ _43_/ZN (INV_X1) โ _58_/ZN (NAND2_X1) โ _60_/ZN (NOR3_X1) โ hwy[1]
Total delay: 0.21 ns | Required: 8.00 ns
_75_/CK (DFF_X1) โ _75_/Q โ _44_/ZN (INV_X1) โ _57_/ZN (OAI22_X1) โ _78_/D (DFF_X1)
Total delay: 0.15 ns | Required: 0.04 ns
| File | Origin | Stage | Purpose |
|---|---|---|---|
t.v |
โ๏ธ Written | Design | Synthesizable RTL |
t_tb.v |
โ๏ธ Written | Simulate | Testbench |
yosys_run.tcl |
โ๏ธ Written | Synthesize | Yosys synthesis script |
t.sdc |
โ๏ธ Written | PDA | Timing constraints |
openroad_run.tcl |
โ๏ธ Written | PDA | OpenROAD PDA script |
t_sim |
๐ค iverilog | Simulate | Compiled binary |
t_synth.v |
๐ค Yosys | Synthesize | Gate-level netlist |
area_report.txt |
๐ค Yosys | Synthesize | Cell & area stats |
t_synth.dot |
๐ค Yosys | Synthesize | Circuit schematic |
t_final.def |
๐ค OpenROAD | PDA | Final placed & routed layout |
# 1. Simulate
$ iverilog -o t_sim t.v t_tb.v && vvp t_sim
# 2. Synthesize
$ yosys -s yosys_run.tcl
# 3. Physical Design
$ openroad openroad_run.tcl