๐Ÿ“˜ Blog Post ยท VLSI Design Flow

From Verilog to Silicon

Building a Traffic Light Controller with open-source EDA tools โ€” Icarus Verilog, Yosys & OpenROAD on the Nangate45 PDK

๐Ÿ“… March 3, 2026 โฑ 8 min read ๐Ÿ”ง Nangate45
Verilog Yosys OpenROAD Icarus Verilog
๐Ÿ“
RTL
t.v
๐Ÿ”ฌ
Simulate
iverilog
โš™๏ธ
Synthesize
Yosys
๐Ÿ—๏ธ
PDA
OpenROAD
โœ…
Layout
DEF

What We're Building

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.

๐Ÿ’ก
Prerequisites: Icarus Verilog, Yosys, and OpenROAD installed. The Nangate45 PDK files (included with OpenROAD's test suite).
01

Design Entry โ€” Synthesizable RTL

A 5-state FSM with counter-based timing delays

Highway
GREEN
S0
Country Road
RED

FSM State Encoding

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
๐Ÿ“„ t.v Verilog
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
โš ๏ธ
Why rewrite? The original used 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).
02

Simulation โ€” Verify Before Synthesis

Compile & run with Icarus Verilog to confirm FSM behavior

๐Ÿ–ฅ๏ธ Terminal
# Compile RTL + testbench
$ iverilog -o t_sim t.v t_tb.v

# Run simulation
$ vvp t_sim

# View waveforms (optional)
$ gtkwave t.vcd

Files at This Stage

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
03

Synthesis โ€” RTL to Gates (Yosys)

Map behavioral Verilog to real Nangate45 standard cells

๐Ÿ“„ yosys_run.tclTcl
# 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
๐Ÿ–ฅ๏ธ Terminal
$ yosys -s yosys_run.tcl

๐Ÿ“š Library File: Nangate45_typ.lib

The Liberty (.lib) file is the heart of technology mapping. It defines every standard cell available in the Nangate45 PDK:

  • Logical function โ€” what each cell does (AND, OR, DFF, BUFโ€ฆ)
  • Timing arcs โ€” input-to-output propagation delay
  • Area โ€” physical size of each cell
  • Power โ€” dynamic and leakage power

dfflibmap uses it to replace generic flip-flops with real DFF_X1 cells. abc uses it to map all combinational logic to real gates.

Synthesis Results

42
Total Cells
8
Flip-Flops
68.9
Area (ยตmยฒ)
14
Cell Types
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

Files Generated

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)
04

Physical Design Automation (OpenROAD)

Floorplan โ†’ Place โ†’ CTS โ†’ Route โ†’ Layout

๐Ÿ“„ t.sdcSDC
# 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]}]

๐Ÿ“š PDK Files Used by OpenROAD

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 vs .lef: Liberty = electrical ("50ps delay, 1.2ยตmยฒ area"). LEF = physical ("pin A at position 0.3,0.7 on metal1"). Yosys needs only .lib. OpenROAD needs both.

PDA Flow Stages

1
Read Design Load liberty, LEF, synthesized netlist, SDC constraints
2
Floorplan Die: 16.5ร—16.5 ยตm โ€” Core: 10.5ร—10.5 ยตm (3ยตm margins)
3
Tapcells Insert substrate/well contacts for latch-up prevention
4
Pin Placement I/O pins on metal2 (vertical) and metal3 (horizontal)
5
Placement Global placement (density 0.6) โ†’ detailed legalization into rows
6
Clock Tree Synthesis Balanced clock distribution using BUF_X4 buffers (3 buffers, depth 2)
7
Routing Global route โ†’ detailed route (284 ยตm total wire, 274 vias)
8
Reports & Output Timing, area, power analysis โ†’ write t_final.def
๐Ÿ–ฅ๏ธ Terminal
$ openroad openroad_run.tcl
05

Final Results

Timing met, zero DRC violations, 85% utilization

โœ…
7.79 ns
Setup Slack (MET)
โœ…
0.11 ns
Hold Slack (MET)
๐Ÿ“
74 ยตmยฒ
Design Area
๐Ÿ“Š
85%
Utilization
๐Ÿ›ก๏ธ
0
DRC Violations
โšก
15.2 ยตW
Total Power

Power Breakdown

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%

Critical Timing Paths

MAX (Setup) Slack: 7.79 ns โœ…
_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
MIN (Hold) Slack: 0.11 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

๐Ÿ“ Complete File Map

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

๐Ÿš€ Quick Start โ€” 3 Commands

# 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