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.

Every warning of that run: OpenROAD 26Q2, the counter at 20 % utilization, create_clock -name clk -period 5 [get_ports clock].
[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.

PrefixToolExample from the counter's run
ODBThe database: reads LEF, DEF and netlistsLEF file read, layers and cells created
STAOpenSTA, the timer, reading the SDCA port named in the SDC is missing
IFPInitialize floorplanAdded 14 rows of 87 sites
TAPTap cell insertionInserted 16 tap cells
PDNPower gridInserting grid
GPLGlobal placementOverflow and wire length per iteration
PPLPin placementPins assigned to the die edges
DPLDetailed placementUtilization 22.8 %, legalized wire length
CTSClock tree synthesisCreated 3 clock buffers
RSZResizer: buffering, sizing, hold repairNo hold violations found
GRTGlobal routingTotal 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.

LayoutThe counter's run and its log27 cells at 20 % utilization, a 5 ns clock, every stage to global routing.
  • 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
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
The counter's run and its logDrawing the layout…
  1. 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.

  2. 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.

  3. Clock tree

    CTS-0018: 3 clock buffers for 8 flops. RSZ-0033: no hold violations to repair. The skew is 0.0040 ns.

  4. 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.

StageCell areaUtilizationWirelength (HPWL)Routed wirelengthWorst max slackTotal negative max slackWorst min slackClock skewRouting usageOverflowCells placed
Floorplan347.8 µm²22.8 %——3.8370 ns0.0000 ns0.4594 ns———16 tap cells; I/O pins not placed yet
Global placement347.8 µm²22.8 %438 µm—3.7467 ns0.0000 ns0.4932 ns——0.100016 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops
Detailed placement347.8 µm²22.8 %505 µm—3.7382 ns0.0000 ns0.5084 ns———16 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops
Clock tree389.1 µm²25.5 %564 µm—3.7348 ns0.0000 ns0.5170 ns0.0040 ns——16 tap cells, 1 buffers and inverters, 18 logic, 8 flip-flops, 3 clock tree
Global route389.1 µm²25.5 %564 µm1,062 µm3.6477 ns0.0000 ns0.5484 ns—5.5 %016 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.

The same run's log, trimmed to the lines the steps quote; ... 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 um

After 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:

OpenROAD 26Q2, the counter at 40 % utilization: the last lines of the log.
[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
  1. 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.

  2. 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.

  3. 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.

STAOpenSTA in OpenROAD 26Q2 · sky130hd tt_025C_1v80 Liberty · simulator service
Edit the constraints, then run them

          
Expected: No paths found. TNS 0 ns
Read 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

Predict the outputThe floorplan's log says [INFO IFP-0105] Number of instances: 27 and [INFO TAP-0005] Inserted 16 tapcells. How many instances does the floorplan report?
create_clock -name clk -period 5 [get_ports clk]
Read the netlist: design.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
ConceptWhat does an ERROR do that a WARNING does not?
ConceptThe timing report says No paths found. What is the most likely reason?
ConceptYou have just read an SDC. Before trusting any slack, you want to know whether every flop has a clock. Which command tells you?
ConceptThe counter has ports clk, rst_n, count[7:0] and tc. Which SDC line will draw a "not found" warning?

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.