Reading a flow log
Read an OpenROAD log by its message IDs, tell a warning that matters from one that does not, and check that a clean timing report actually timed something.
- Lesson
- L1.6
- Time
- 20 min
- Runs on
- OpenROAD
- Check
- 5 questions
The counter of R2.4 went from floorplan to global route with no failing path, though its SDC named the clock port clock and the netlist says clk. The first warning in the log said so.
[WARNING STA-0366] port 'clock' not found.
[WARNING IFP-0028] Core area lower left (5.000, 5.000) snapped to (5.060, 5.440).
[WARNING CTS-0083] No clock nets have been found.
[WARNING CTS-0082] No valid clock nets in the design.
[WARNING STA-0450] virtual clock clk can not be propagated.With no source the clock reached none of the 8 flops, the clock tree stage built nothing, and a total negative slack of 0 meant that nothing was timed. The warnings were there; nobody read them.
Every message has a tool and a number
OpenROAD runs one tool per stage inside one program, and every tool writes to the same log. A message looks like [WARNING IFP-0028] text: a severity, a tool prefix and a number. The ID is stable, so you can search for it in the log and in the documentation.
| Prefix | Tool | Example from the counter's run |
|---|---|---|
| ODB | The database: reads LEF, DEF and netlists | LEF file read, layers and cells created |
| STA | OpenSTA, the timer, reading the SDC | A port named in the SDC is missing |
| IFP | Initialize floorplan | Added 14 rows of 87 sites |
| TAP | Tap cell insertion | Inserted 16 tap cells |
| PDN | Power grid | Inserting grid |
| GPL | Global placement | Overflow and wire length per iteration |
| PPL | Pin placement | Pins assigned to the die edges |
| DPL | Detailed placement | Utilization 22.8 %, legalized wire length |
| CTS | Clock tree synthesis | Created 3 clock buffers |
| RSZ | Resizer: buffering, sizing, hold repair | No hold violations found |
| GRT | Global routing | Total wirelength 1062 µm |
The tool prefixes in the counter's runs, in the order they appear. The SDC is read before the floorplan, so a timer warning comes early.
Three severities matter: INFO reports progress and numbers. A WARNING means the tool did something you may not have meant, and carried on. An ERROR stops the script: the stages after it never run.
A long run prints thousands of lines, and most are INFO. Search for WARNING and ERROR first and list the distinct IDs. A warning you have seen before, for a reason you know, can be noted and passed over. A new one needs an answer before you trust anything after it.
What to read after each stage
A log of a few hundred lines has a handful worth reading. Step through the counter's run with the lines that describe each stage.
- Tap cells
- Logic
- Buffers and inverters
- Flip-flops
- Clock tree
- Clock nets
- Routing usage per GCell: under 30 %, 30-60 %, 60-90 %, 90 % or more
- Power stripes
- I/O pins
- Stage
- Floorplan
- Cell area
- 347.8 µm²
- Utilization
- 22.8 %
- Worst max slack
- 3.8370 ns
- Total negative max slack
- 0.0000 ns
- Worst min slack
- 0.4594 ns
- Stage
- Global placement
- Cell area
- 347.8 µm²
- Utilization
- 22.8 %
- Wirelength (HPWL)
- 438 µm
- Worst max slack
- 3.7467 ns
- Total negative max slack
- 0.0000 ns
- Worst min slack
- 0.4932 ns
- Overflow
- 0.1000
- Stage
- Detailed placement
- Cell area
- 347.8 µm²
- Utilization
- 22.8 %
- Wirelength (HPWL)
- 505 µm
- Worst max slack
- 3.7382 ns
- Total negative max slack
- 0.0000 ns
- Worst min slack
- 0.5084 ns
- Stage
- Clock tree
- Cell area
- 389.1 µm²
- Utilization
- 25.5 %
- Wirelength (HPWL)
- 564 µm
- Worst max slack
- 3.7348 ns
- Total negative max slack
- 0.0000 ns
- Worst min slack
- 0.5170 ns
- Clock skew
- 0.0040 ns
- Stage
- Global route
- Cell area
- 389.1 µm²
- Utilization
- 25.5 %
- Wirelength (HPWL)
- 564 µm
- Routed wirelength
- 1,062 µm
- Worst max slack
- 3.6477 ns
- Total negative max slack
- 0.0000 ns
- Worst min slack
- 0.5484 ns
- Routing usage
- 5.5 %
- Overflow
- 0
- Floorplan
IFP-0001: 14 rows of 87 sites.IFP-0104: the logic fills 21.5 % of the core.TAP-0005: 16 tap cells. Check the core is the size you meant. - Placement
DPL-0006: utilization 22.8 % with the taps. The legalized wire length is 504.7 µm, up from 437.9 µm after global placement. A large jump means cells moved far. - Clock tree
CTS-0018: 3 clock buffers for 8 flops.RSZ-0033: no hold violations to repair. The skew is 0.0040 ns. - Global route
GRT-0018: 1062 µm of routed wire. The congestion table ends with the overflow: 0 here. Any other value means some regions have more wires than tracks.
Read the layout as text
modn: die 50.49 × 50.49 µm, core 40.02 × 38.08 µm, 14 rows of 2.72 µm, 11 signal pins.
| Stage | Cell area | Utilization | Wirelength (HPWL) | Routed wirelength | Worst max slack | Total negative max slack | Worst min slack | Clock skew | Routing usage | Overflow | Cells placed |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Floorplan | 347.8 µm² | 22.8 % | — | — | 3.8370 ns | 0.0000 ns | 0.4594 ns | — | — | — | 16 tap cells; I/O pins not placed yet |
| Global placement | 347.8 µm² | 22.8 % | 438 µm | — | 3.7467 ns | 0.0000 ns | 0.4932 ns | — | — | 0.1000 | 16 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops |
| Detailed placement | 347.8 µm² | 22.8 % | 505 µm | — | 3.7382 ns | 0.0000 ns | 0.5084 ns | — | — | — | 16 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops |
| Clock tree | 389.1 µm² | 25.5 % | 564 µm | — | 3.7348 ns | 0.0000 ns | 0.5170 ns | 0.0040 ns | — | — | 16 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops, 3 clock tree |
| Global route | 389.1 µm² | 25.5 % | 564 µm | 1,062 µm | 3.6477 ns | 0.0000 ns | 0.5484 ns | — | 5.5 % | 0 | 16 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops, 3 clock tree |
Measured with OpenROAD 26Q2 on sky130hd; the numbers in each step are the log's.
... marks the lines left out.[INFO IFP-0001] Added 14 rows of 87 site unithd.
[INFO IFP-0102] Core area: 1523.962 um^2
[INFO IFP-0103] Total instances area: 327.814 um^2
[INFO IFP-0104] Effective utilization: 0.215
[INFO IFP-0105] Number of instances: 27
[INFO TAP-0005] Inserted 16 tapcells.
...
[INFO DPL-0006] Core area: 1523.96 um^2, Instances area: 347.83 um^2, Utilization: 22.8%
...
[INFO CTS-0018] Created 3 clock buffers.
...
[INFO RSZ-0033] No hold violations found.
...
[INFO GRT-0018] Total wirelength: 1062 umAfter every stage, read three things. First the warnings: count them by ID and read each new ID once. Then read the stage's summary lines and, last, one sanity report, such as the worst slack or the cell area.
Read the numbers against what you expect: the core area should match the utilization you asked for. The instances should be the netlist's 27 cells plus the taps. A clock tree for 8 flops should have a few buffers, not hundreds. A number far from your estimate is a question, even when no message flags it.
Errors stop the run; warnings let it finish
Run the same counter at 40 % utilization, and the run stops in the floorplan with an error:
[INFO IFP-0001] Added 10 rows of 62 site unithd.
[INFO TAP-0005] Inserted 12 tapcells.
[ERROR PDN-0185] Insufficient width (28.52 um) to add straps on layer met4 in grid "grid" with total strap width 15.2 um and offset 13.6 um.The prefix names the stage: PDN, the power grid. The text names the cause. The core is 28.52 µm wide, and the met4 straps need 13.6 + 15.2 = 28.8 µm. Nothing after the error ran, so there is no placement to look at. A lower utilization makes the core wider, and the run goes through.
Warnings are harder, because the run finishes. The snapped core corner, IFP-0028, is harmless: L1.5 explains it. The missing clock port of the opening story is not. STA-0366 left clk with no source, a virtual clock that exists only in the constraints. So CTS-0083 found no clock net, and STA-0450 could not propagate the clock. Treat every warning from the timer as a question to answer.
The command that answers it is check_setup, run right after reading the SDC. It lists unclocked registers, inputs and outputs with no delay, and unconstrained endpoints: pins where a path ends and no check applies. Here it reports 8 unclocked register pins, one per flop, and 17 unconstrained endpoints.
Asked in interviews
Your flow finished with no timing violations. What do you check before believing it?
That something was timed: the clocks exist on the right ports, check_setup shows no unclocked registers or unexpected unconstrained endpoints, and the warnings were read, especially the timer's.
How do you find unconstrained paths?
check_setup lists unclocked registers and unconstrained endpoints; report_checks -unconstrained prints the paths themselves. Then add the missing clock, input delay or output delay.
What do you look at in a placement log?
Utilization, the placer's final overflow and wire length, and the legalizer's displacement and wire length change. A large legalization jump or a high overflow means the core is too full.
Try it
This is the opening story's SDC in a timing run. Run it: Output shows warning 366, the same message standalone OpenSTA prints without the STA- prefix. The report says "No paths found.", and check_setup lists the unclocked flops.
Change clock to clk and run again. The flops are clocked, the report has paths, and check_setup keeps only the inputs and outputs with no delay: the outputs are still unconstrained endpoints.
Run to draw the timing paths here.
No paths found. TNS 0 nsRead the netlist: modn.v
module modn (clk, rst_n, count, tc);
input clk;
input rst_n;
output [7:0] count;
output tc;
wire _00_, _01_, _02_, _03_, _04_, _05_, _06_, _07_, _08_;
wire _09_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_;
sky130_fd_sc_hd__clkinv_1 _18_ (.A(count[0]), .Y(_00_));
sky130_fd_sc_hd__and3_1 _19_ (.A(count[0]), .B(count[2]), .C(count[1]), .X(_08_));
sky130_fd_sc_hd__nor2_1 _20_ (.A(_10_), .B(_14_), .Y(_05_));
sky130_fd_sc_hd__xor2_1 _21_ (.A(count[4]), .B(_09_), .X(_04_));
sky130_fd_sc_hd__xnor2_1 _22_ (.A(count[3]), .B(_08_), .Y(_15_));
sky130_fd_sc_hd__nor2_1 _23_ (.A(tc), .B(_15_), .Y(_03_));
sky130_fd_sc_hd__a21oi_1 _24_ (.A1(count[0]), .A2(count[1]), .B1(count[2]), .Y(_16_));
sky130_fd_sc_hd__nor2_1 _25_ (.A(_08_), .B(_16_), .Y(_02_));
sky130_fd_sc_hd__xor2_1 _26_ (.A(count[0]), .B(count[1]), .X(_01_));
sky130_fd_sc_hd__a41oi_1 _27_ (.A1(count[6]), .A2(count[5]), .A3(count[4]), .A4(_09_), .B1(count[7]), .Y(_17_));
sky130_fd_sc_hd__a311oi_1 _28_ (.A1(count[6]), .A2(count[7]), .A3(_10_), .B1(tc), .C1(_17_), .Y(_07_));
sky130_fd_sc_hd__and4_1 _29_ (.A(count[0]), .B(count[3]), .C(count[2]), .D(count[1]), .X(_09_));
sky130_fd_sc_hd__and3_1 _30_ (.A(count[5]), .B(count[4]), .C(_09_), .X(_10_));
sky130_fd_sc_hd__and4_1 _31_ (.A(count[6]), .B(count[5]), .C(count[4]), .D(_09_), .X(_11_));
sky130_fd_sc_hd__nor3b_1 _32_ (.A(count[5]), .B(count[4]), .C_N(count[6]), .Y(_12_));
sky130_fd_sc_hd__and4b_1 _33_ (.A_N(count[3]), .B(count[7]), .C(_08_), .D(_12_), .X(tc));
sky130_fd_sc_hd__a31oi_1 _34_ (.A1(count[5]), .A2(count[4]), .A3(_09_), .B1(count[6]), .Y(_13_));
sky130_fd_sc_hd__nor3_1 _35_ (.A(_11_), .B(tc), .C(_13_), .Y(_06_));
sky130_fd_sc_hd__a21oi_1 _36_ (.A1(count[4]), .A2(_09_), .B1(count[5]), .Y(_14_));
sky130_fd_sc_hd__dfrtp_1 _37_ (.CLK(clk), .D(_00_), .Q(count[0]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _38_ (.CLK(clk), .D(_01_), .Q(count[1]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _39_ (.CLK(clk), .D(_02_), .Q(count[2]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _40_ (.CLK(clk), .D(_03_), .Q(count[3]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _41_ (.CLK(clk), .D(_04_), .Q(count[4]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _42_ (.CLK(clk), .D(_05_), .Q(count[5]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _43_ (.CLK(clk), .D(_06_), .Q(count[6]), .RESET_B(rst_n));
sky130_fd_sc_hd__dfrtp_1 _44_ (.CLK(clk), .D(_07_), .Q(count[7]), .RESET_B(rst_n));
endmodule
Check yourself
Remember
- Every OpenROAD message has a severity, a tool prefix and a number, such as [WARNING STA-0366]; search the log by ID.
- An ERROR stops the run at that stage; a WARNING lets it finish, so a finished run can still be wrong.
- After each stage read the warnings, the stage's summary lines and one sanity report.
- A clean timing report may mean nothing was timed: run check_setup after reading the SDC.