This project demonstrates a complete RTL-to-GDSII physical design flow for a custom 8-bit synchronous counter written in Verilog.
The design was functionally verified using a self-checking testbench and then implemented from RTL to final GDSII using OpenROAD-flow-scripts on the Nangate45 platform.
The design is an 8-bit synchronous counter with:
clk: clock inputrst_n: active-low resetenable: counter enablecount[7:0]: 8-bit counter output
Counter behavior:
always @(posedge clk) begin
if (!rst_n)
count <= 8'd0;
else if (enable)
count <= count + 8'd1;
endA self-checking Verilog testbench was created to verify the RTL behavior.
The testbench checks:
- reset behavior
- hold behavior when
enable = 0 - counting behavior when
enable = 1 - reset after counting
Simulation result:
TEST PASSED: my_counter RTL works
Waveform output:
sim/my_counter.vcd
The design was taken through the following physical design stages:
RTL Verilog
→ Logic Synthesis
→ Floorplanning
→ Placement
→ Clock Tree Synthesis
→ Global Routing
→ Detailed Routing
→ Parasitic Extraction
→ Static Timing Analysis
→ Power Analysis
→ Final GDSII Generation
| Item | Description |
|---|---|
| Flow | OpenROAD-flow-scripts |
| Synthesis Tool | Yosys |
| Timing Tool | OpenSTA |
| Physical Design Tool | OpenROAD |
| GDS Generation | KLayout / def2stream |
| Platform | Nangate45 |
| Design | my_counter |
| RTL Language | Verilog |
pd_project_my_counter/
├── src/
│ └── my_counter.v
├── sim/
│ ├── tb_my_counter.v
│ ├── run_sim.sh
│ └── my_counter.vcd
├── config/
│ ├── config.mk
│ └── constraint.sdc
├── reports/
│ ├── 6_finish.rpt
│ ├── 5_route_drc.rpt
│ └── ...
├── results/
│ ├── 6_final.gds
│ ├── 6_final.def
│ ├── 6_final.v
│ ├── 6_final.sdc
│ ├── 6_final.spef
│ └── 6_final.odb
├── images/
│ ├── final_all.webp
│ ├── final_routing.webp
│ ├── final_placement.webp
│ └── final_clocks.webp
└── README.md
Final layout image:
Final routing image:
| File | Meaning |
|---|---|
6_final.gds |
Final GDSII layout |
6_final.def |
Final physical design database in DEF format |
6_final.v |
Final gate-level netlist |
6_final.sdc |
Final timing constraints |
6_final.spef |
Extracted parasitics after routing |
6_final.odb |
OpenROAD database |
| Metric | Value |
|---|---|
| WNS | 0.00 ns |
| TNS | 0.00 ns |
| Worst Slack | 1.40 ns |
| Setup Violations | 0 |
| Hold Violations | 0 |
| Minimum Clock Period | 0.60 ns |
| Estimated Fmax | 1679.78 MHz |
| Critical Path Delay | 0.1953 ns |
| Critical Path Slack | 1.4047 ns |
The routed design achieved timing closure with no setup or hold violations.
| Check | Result |
|---|---|
| Max Slew Violations | 0 |
| Max Fanout Violations | 0 |
| Max Capacitance Violations | 0 |
| Route DRC Violations | 0 reported |
The route DRC report is empty, which indicates that no route DRC violations were reported by the OpenROAD detailed routing flow.
| Group | Power | Percentage |
|---|---|---|
| Sequential | 0.0293 mW | 49.8% |
| Combinational | 0.00545 mW | 9.3% |
| Clock | 0.0241 mW | 41.0% |
| Total | 0.0589 mW | 100% |
Through this project, I learned:
- how to write a simple synthesizable RTL module;
- how to verify RTL behavior using a self-checking testbench;
- how to generate and inspect a VCD waveform;
- how to create timing constraints using SDC;
- how to configure a custom design in OpenROAD-flow-scripts;
- how synthesis maps RTL into standard cells;
- how placement, CTS, and routing are applied to a custom RTL design;
- how to read timing, power, DRC, DEF, SPEF, and GDS results.
The RTL design and testbench in this repository were written by me.
The physical design flow uses OpenROAD-flow-scripts and the Nangate45 open cell library.

