Every stage
Each case shows the tail of a real run, ending where the tool stopped or warned. Say what caused it, or what to do about it. A case you miss returns later in the round and starts its schedule over; one you get right returns after 1, 3, 7, then 21 days. Keys 1 to 4 choose an option, h shows a hint, and Enter moves on. Progress is stored in this browser.
All 41 cases in this drill, with answers
-
The run stopped here, one second in. What is the cause?
1_1_yosys_canonicalize log
make: *** No rule to make target '/nonexistent/none.lib', needed by 'results/nangate45/gcd/bad_lib/1_1_yosys_canonicalize.rtlil'. Stop.
A file the flow was told to read does not exist.Hint: Read what make says it was trying to build, and what needed it.
Make treats every input as either a file on disk or something it knows how to build. A path that is neither produces this message, and it names both the missing path and the thing that wanted it. The stage named is not at fault: it is simply the first one that needed the file.
LIB_FILES = $(PLATFORM_DIR)/lib/NangateOpenCellLibrary_typical.lib
-
Synthesis finished and then the run stopped. What happened?
1_synth log
Time spent: 47% 1x abc (0 sec), 8% 21x opt_clean (0 sec), ... Elapsed time: 0:00.33[h:]min:sec. CPU time: user 0.28 sys 0.05 (99%). Peak memory: 45056KB. Log Ext Elapsed/s Peak Memory/MB sha1sum result [0:20) 1_2_yosys .v 0 44 756ad24f74de658d5044 cp /OpenROAD-flow-scripts/flow/designs/nangate45/gcd/constraint.sdc ./results/nangate45/gcd/bad_techlef/1_2_yosys.sdc make: *** No rule to make target '/nonexistent/none.tech.lef', needed by 'results/nangate45/gcd/bad_techlef/1_synth.odb'. Stop.
The technology file the next stage needs is missing.Hint: Compare the stage that finished with the file make was looking for.
Synthesis completed: its statistics and its output file are in the log above the error. The failure belongs to the step that turns that netlist into a database, which needs the layers and sites the technology file defines. A missing input is reported when it is first needed, not when it was configured, which is why the stage that stops is rarely the culprit.
TECH_LEF = $(PLATFORM_DIR)/lef/NangateOpenCellLibrary.tech.lef
-
What is the cause, and what does it say about the configuration?
2_1_floorplan log
========================================================================== Floorplan check_setup -------------------------------------------------------------------------- number instances in verilog is 521 [INFO IFP-0107] Defining die area using utilization: 55.00% and aspect ratio: 1. [ERROR IFP-0018] Unable to find site: NOSUCHSITE Error: floorplan.tcl, 91 IFP-0018 Elapsed time: 0:00.24[h:]min:sec. CPU time: user 0.21 sys 0.04 (104%). Peak memory: 114796KB.
The site the rows are built from is not defined in the technology file.Hint: The message names something it looked for. Where would that be defined?
A site is the unit cell of a placement row, and the floorplan needs one by name before it can build rows at all. The name comes from the platform configuration and has to match a
SITEin the technology file exactly. The line above shows the die area was already worked out, so everything before this was fine.PLACE_SITE = FreePDK45_38x28_10R_NP_162NW_34O
-
The constraints have just been read. What do these warnings mean?
1_synth log
read_sdc ./results/nangate45/gcd/no_clock/1_2_yosys.sdc [WARNING STA-0351] clock 'core_clock' not found. [WARNING STA-0351] clock 'vclk_core_clock' not found. [WARNING STA-0138] clock arg 'vclk_core_clock' clock not found. [WARNING STA-0138] clock arg 'vclk_core_clock' clock not found.
Later constraints name a clock that was never created.Hint: Ask what kind of command names a clock without creating one.
Latency, uncertainty, and the port delays all refer to a clock by name, and each one warns separately when that name is unknown. They are warnings, not errors, so the run carries on and the consequences appear several stages later. This is the earliest point at which the mistake is visible.
create_clock -name core_clock -period 0.46 [get_ports clk]
-
The run is carrying on from here. What will the timing reports look like?
2_1_floorplan log
========================================================================== Floorplan check_setup -------------------------------------------------------------------------- Warning: There are 35 unclocked register/latch pins. Warning: There are 53 unconstrained endpoints. number instances in verilog is 521
Empty and perfect, because almost nothing is being checked.Hint: Ask what a timing check needs at both ends of a path.
An unclocked register pin has no clock defined on it, so no path through it can be timed, and an unconstrained endpoint is one nothing checks. Worst negative slack then comes back as zero and the run looks like its best ever. A clean run reports neither of these lines, which is why this check is printed at the start of the floorplan.
check_setup report_checks -unconstrained
-
Clock tree synthesis just ran. What happened, and what does it cost?
3_1_cts log
clock_tree_synthesis -sink_clustering_enable -repair_clock_nets [INFO CTS-0050] Root buffer is CLKBUF_X3. [INFO CTS-0051] Sink buffer is CLKBUF_X3. [INFO CTS-0052] The following clock buffers will be used for CTS: CLKBUF_X3 [INFO CTS-0049] Characterization buffer is CLKBUF_X3. [WARNING CTS-0083] No clock nets have been found. [INFO CTS-0008] TritonCTS found 0 clock nets. [WARNING CTS-0082] No valid clock nets in the design. [INFO CTS-0500] Runtime: 0.42sThere was no clock to build a tree from, so the clock stays unbuffered.Hint: The buffers were chosen. Ask what they were going to be used on.
The tool picked its buffers, looked for nets driven by a defined clock, and found none. It reports this as a warning and exits cleanly, so the run continues to routing with the clock driven by whatever the netlist had. Everything downstream, from skew to hold repair, is then meaningless.
# the clock has to exist before this stage create_clock -name core_clock -period 0.46 [get_ports clk]
-
Placement failed on three instances. What is the real cause?
5_1_grt log
global_route -start_incremental detailed_placement [INFO DPL-0006] Core area: 1161.89 um^2, Instances area: 1143.27 um^2, Utilization: 98.4% [INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. [INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 730 Diamond Move Success: 727 ( 99.59%) Diamond Move Failure: 3 Rip-up and replace Success: 0 ( 0.00% of diamond failures) Rip-up and replace Failure: 3 Total Placement Failures: 3 --------------------------------------- [INFO DPL-0034] Detailed placement failed on the following 3 instances: [INFO DPL-0035] dpath.a_reg.out[0]$_DFFE_PP_ [INFO DPL-0035] rebuffer312 [INFO DPL-0035] dpath.b_reg.out[0]$_DFFE_PP_ [ERROR DPL-0036] Detailed placement failed inside DPL. Error: global_route.tcl, 150 DPL-0036 Elapsed time: 0:27.08[h:]min:sec. CPU time: user 419.61 sys 0.93 (1552%). Peak memory: 294840KB. make[1]: *** [Makefile:548: do-5_1_grt] Error 1 make: *** [Makefile:548: results/nangate45/gcd/fast_clock/5_1_grt.odb] Error 2
Timing repair grew the netlist until the rows were full.Hint: Compare the utilization here with the 55 percent the floorplan was built for.
The rows were built for 55 percent utilization and this run is at 98.4 percent, against about 61 percent on a healthy run of the same design. Nothing added that area except repair, which buffers and upsizes until it meets the constraint or runs out of room. The three instances named are where it finally failed, not why. Follow the utilization back through the log and the cause is a clock period nothing could meet.
# either give repair a reachable target create_clock -name core_clock -period 0.46 [get_ports clk] # or give it room to work in export CORE_UTILIZATION = 40
-
This run finished cleanly. Is there anything here to act on?
5_2_route log
global_route -end_incremental -congestion_report_file ./reports/nangate45/gcd/good/congestion_post_recover_power.rpt Repair antennas... [WARNING GRT-0246] No diode with LEF class CORE ANTENNACELL found. [INFO ANT-0002] Found 0 net violations. [INFO ANT-0001] Found 0 pin violations. Estimate parasitics...
Yes: antenna repair has no diode to insert, so it fixes nothing.Hint: Read the first line, then ask how the two lines under it were able to say zero.
The tool looked for a cell of the antenna class and found none, so the repair step is doing nothing. On this design nothing was violating, so it cost nothing. On a design that does violate, the same warning means the violations stay and are found much later, at sign-off. A warning in a clean run is worth reading precisely because nothing failed.
# name a diode from the platform so repair has something to insert export ANTENNA_CELL_NAME = ANTENNA_X1
-
Hold repair ran to its last iteration. What is this table telling you?
4_1_cts log
[INFO RSZ-0046] Found 35 endpoints with hold violations. Iteration | Resized | Buffers | Cloned Gates | Area | WNS | TNS | Endpoint -------------------------------------------------------------------------------------- 0 | 0 | 0 | 0 | +0.0% | -0.186 | -5.960 | dpath.b_reg.out[9]$_DFFE_PP_/D 10 | 0 | 15 | 0 | +1.7% | -0.180 | -5.704 | dpath.b_reg.out[3]$_DFFE_PP_/D 20 | 0 | 1 | 0 | +3.0% | -0.172 | -5.567 | dpath.b_reg.out[1]$_DFFE_PP_/D 30 | 0 | 0 | 0 | +3.5% | -0.172 | -5.481 | dpath.b_reg.out[1]$_DFFE_PP_/D final | 0 | 0 | 0 | +3.7% | -0.172 | -5.434 | dpath.b_reg.out[1]$_DFFE_PP_/D -------------------------------------------------------------------------------------- [WARNING RSZ-0066] Unable to repair all hold violations.Repair is buying almost nothing for the area it is spending.Hint: Compare the first row's numbers with the last row's, and watch the area column.
Thirty iterations recovered 0.014 nanoseconds of the 0.186 that was failing, and spent 3.7 percent more area doing it. That shape means the requirement is not reachable by buffering, so the answer is upstream: on this run, 0.30 nanoseconds of hold uncertainty had been added to the constraints, which is far more than any insertion can absorb. A healthy run of this design reports no hold violations at all.
# uncertainty should reflect jitter and the timer's margin, not a guess set_clock_uncertainty -hold 0.03 [get_clocks core_clock]
-
The clock is fine and the run continues. What is not being checked?
2_1_floorplan log
========================================================================== Floorplan check_setup -------------------------------------------------------------------------- Warning: There are 35 input ports missing set_input_delay. Warning: There are 18 output ports missing set_output_delay. Warning: There are 18 unconstrained endpoints. number instances in verilog is 521
Every path that starts or ends at a port.Hint: Count the ports named, and ask what a path from a port needs before it can be timed.
A port has no arrival time of its own, so without an input delay the timer has nothing to start from, and without an output delay nothing to finish against. Those paths simply vanish from the reports. The interface is usually the tightest part of a block, so this is a comfortable way to close timing on a design that will fail in the system.
set_input_delay [expr 0.2 * $clk_period] -clock $clk [all_inputs -no_clocks] set_output_delay [expr 0.2 * $clk_period] -clock $clk [all_outputs]
-
Placement stopped before it started. What does this mean?
3_1_place_gp_skip_io log
read_sdc ./results/nangate45/gcd/tiny_die/2_floorplan.sdc source /OpenROAD-flow-scripts/flow/platforms/nangate45/setRC.tcl [INFO GPL-0022] Initialize gpl and calculate uniform density. [ERROR FLW-0024] Place density exceeds 1.0 (current PLACE_DENSITY_LB_ADDON = 0.20). Please check if the value of PLACE_DENSITY_LB_ADDON is between 0 and 0.99. Error: global_place_skip_io.tcl, 19 FLW-0024 Elapsed time: 0:00.43[h:]min:sec. CPU time: user 4.28 sys 0.04 (1013%). Peak memory: 116140KB. make[1]: *** [Makefile:458: do-3_1_place_gp_skip_io] Error 1 make: *** [Makefile:458: results/nangate45/gcd/tiny_die/3_1_place_gp_skip_io.odb] Error 2
The target density works out above one, which is not a thing.Hint: The number it complains about is computed, not something you set directly.
The placer works to a density target built from the design's utilization plus an allowance. Ask for 95 percent utilization and add the allowance and the target passes one, meaning the cells would have to overlap. The run stops before placing anything, which is the useful behaviour: the floorplan is what needs changing.
export CORE_UTILIZATION = 55 export PLACE_DENSITY_LB_ADDON = 0.20
-
The mapper failed with a status code and nothing else. What do you do?
1_2_yosys log
10. Executing ABC pass (technology mapping using ABC). 10.1. Extracting gate netlist of module `\gcd' to `<abc-temp-dir>/input.blif'.. ERROR: ABC failed with status 8B Elapsed time: 0:00.37[h:]min:sec. CPU time: user 0.24 sys 0.06 (81%). Peak memory: 42496KB. make[1]: *** [Makefile:266: do-yosys] Error 1 make: *** [Makefile:277: results/nangate45/gcd/no_buffers/1_2_yosys.v] Error 2
Read the command above it, which lists what was excluded.Hint: The tool says nothing useful, so read the line that invoked it.
A bare status code carries no information, so the next move is to read what the tool was asked to do. The command line here excludes every buffer and clock buffer in the library, which leaves the mapper unable to finish. Passes before it completed normally, so the netlist itself is fine. Reading the invocation is the habit worth keeping.
# keep the buffers the mapper and every later stage need export DONT_USE_CELLS = AOI211_X1 OAI211_X1
-
What is the cause, and where do you look for it?
1_1_yosys_canonicalize log
6.12. Analyzing design hierarchy.. ERROR: Module `\missing_helper' referenced in module `\Subtractor_0x422b1f52edd46a85' in cell `\u_helper' is not part of the design. Elapsed time: 0:00.09[h:]min:sec. CPU time: user 0.07 sys 0.02 (99%). Peak memory: 38144KB. make[1]: *** [Makefile:271: do-yosys-canonicalize] Error 1 make: *** [Makefile:274: results/nangate45/gcd/undef_module/1_1_yosys_canonicalize.rtlil] Error 2
A module is instantiated that no source file defines.Hint: The message names three things. Ask which of them is the one that does not exist.
The hierarchy check walks from the top down and stops at the first instance whose module it cannot find. It names the missing module, the module that instantiates it, and the instance, which is everything needed to find the line. The usual causes are a file left out of the file list, a typo, and a cell that should have been declared a black box.
# add the file that defines it, or declare it a black box (* blackbox *) module missing_helper (input clk); endmodule
-
The design's files have not moved. Why is this path being looked for?
1_1_yosys_canonicalize log
make: *** No rule to make target '/OpenROAD-flow-scripts/flow/designs/src/not_gcd/gcd.v', needed by 'results/nangate45/not_gcd/wrong_top/1_1_yosys_canonicalize.rtlil'. Stop.
The design's name is used to build the path, and it is wrong.Hint: Compare the directory in the path with the design you meant to run.
The same message as a missing library, from a different cause. The name is substituted into the source directory, the results directory, and the top module, so one typo makes the flow look in a directory that never existed. Reading which part of the path looks wrong is faster than checking whether the file is there.
export DESIGN_NAME = gcd
-
The constraints do create a clock. What has this warning cost?
1_synth log
link_design gcd read_sdc ./results/nangate45/gcd/bad_port/1_2_yosys.sdc [WARNING STA-0366] port 'nosuchport' not found. source /OpenROAD-flow-scripts/flow/platforms/nangate45/setRC.tcl eliminate_dead_logic Removed 0 unused instances and 0 unused nets.
The clock was created on nothing, so it clocks nothing.Hint: Ask what `create_clock` does when the object list it is given is empty.
A port query that matches nothing returns an empty list, and creating a clock on an empty list is legal: it makes a virtual clock. The constraints file looks right, the clock is defined, and not one register is clocked. One warning line, among the normal output of reading the constraints, is the whole of the evidence.
set clk_port_name clk
-
Two clocks report the same thing. Which one is the problem?
4_1_cts log
[INFO GRT-0014] Routed nets: 612 [INFO GRT-0303] Global routing runtime = 00:00:00 [WARNING STA-0450] virtual clock core_clock can not be propagated. [WARNING STA-0450] virtual clock vclk_core_clock can not be propagated. estimate_parasitics -global_routing Perform buffer insertion and gate resizing...
The core clock, since only the interface one should be virtual.Hint: One of these two clocks is meant to be virtual. Ask which, and why.
A constraints file usually defines a second, source-less clock for the port delays, so the message about it is expected. The same message about the clock that should drive the registers means it never found its port. Reading warnings is often like this: the line is not new, the name in it is.
create_clock -name core_clock -period 0.46 [get_ports clk] create_clock -name vclk_core_clock -period 0.46
-
The run completed after this. What has it silently built?
1_1_yosys_canonicalize log
6.5. Executing AST frontend in derive mode using pre-parsed AST for module `\RegRst_0x9f365fdf6c8998a'. 6.6. Executing AST frontend in derive mode using pre-parsed AST for module `\RegEn_0x68db79c4ec1d6e5b'. 6.7. Executing AST frontend in derive mode using pre-parsed AST for module `\Subtractor_0x422b1f52edd46a85'. /tmp/rtl/gcd_latch.v:760: Warning: Identifier `\req_val' is implicitly declared. /tmp/rtl/gcd_latch.v:760: Warning: Identifier `\req_msg' is implicitly declared. /tmp/rtl/gcd_latch.v:760: Warning: Range select [15:0] out of bounds on signal `\req_msg': Setting all 16 result bits to undef. 6.8. Executing AST frontend in derive mode using pre-parsed AST for module `\Mux_0xdd6473406d1a99a'.
A one-bit wire where a sixteen-bit one was meant.Hint: Ask what width a signal gets when nothing declares it.
Verilog lets an undeclared identifier become an implicit one-bit wire, so a misspelled name never stops the run. The third line is the consequence: the range select cannot fit, so the bits become undefined. This is the kind of warning that is worth failing a build on, because everything downstream is built on it and none of it complains again.
// declare what you use, and fail the build on implicit declarations wire [15:0] req_msg;
-
What is wrong, and where was it decided?
4_1_cts log
clock_tree_synthesis -sink_clustering_enable -repair_clock_nets -buf_list NOSUCHBUF_X1 [ERROR CTS-0126] No physical master cell found for buffer NOSUCHBUF_X1. Error: cts.tcl, 36 CTS-0126 Elapsed time: 0:00.23[h:]min:sec. CPU time: user 0.19 sys 0.05 (100%). Peak memory: 114032KB. make[1]: *** [Makefile:511: do-4_1_cts] Error 1 make: *** [Makefile:511: results/nangate45/gcd/no_clkbuf/4_1_cts.odb] Error 2
The buffer list names a cell the library does not contain.Hint: The name in the message also appears in the command above it.
The buffer list overrides the tool's own choice, and nothing checks the names until they are needed. The command line is printed directly above the error, which is where to read the name from. The same failure follows a library swap, when the new library spells its buffers differently.
export CTS_BUF_LIST = CLKBUF_X1 CLKBUF_X2 CLKBUF_X3
-
The grid could not be built. What was it asked for?
2_4_floorplan_pdn log
[ERROR PDN-1023] Unable to find metalX layer. Error: pdn.tcl, 6 PDN-1023 Elapsed time: 0:00.22[h:]min:sec. CPU time: user 0.19 sys 0.03 (100%). Peak memory: 114348KB. make[1]: *** [Makefile:429: do-2_4_floorplan_pdn] Error 1 make: *** [Makefile:429: results/nangate45/gcd/bad_pdn/2_4_floorplan_pdn.odb] Error 2
A layer the technology file does not define.Hint: The layer it names is not one the technology has.
The grid definition names the layers its straps and rings are drawn on, and those names have to exist in the technology file. It is the usual failure when a grid written for one platform is pointed at another, since every process names its metals differently.
# name layers this technology actually has add_pdn_stripe -layer metal7 -width 1.4 -pitch 40 -offset 2
-
Only one variable was changed, to route on fewer layers. What broke?
2_1_floorplan log
source /OpenROAD-flow-scripts/flow/platforms/nangate45/fastroute.tcl [ERROR ODB-0137] In argument -clock_layers, min routing layer is greater than max routing layer. Error: floorplan.tcl, 111 ODB-0137 Elapsed time: 0:00.23[h:]min:sec. CPU time: user 0.21 sys 0.05 (109%). Peak memory: 116372KB. make[1]: *** [Makefile:415: do-2_1_floorplan] Error 1 make: *** [Makefile:415: results/nangate45/gcd/few_layers/2_1_floorplan.odb] Error 2
The clock's lowest layer is now above the highest layer allowed.Hint: Two limits are being compared. One of them was not changed with the other.
A platform routes its clocks on upper layers on purpose, so it sets a minimum layer for them. Lower the maximum for the whole design and the two settings cross, which the floorplan catches before anything is built. Retargeting a design to a thinner stack means moving both limits.
export MAX_ROUTING_LAYER = metal3 export MIN_CLK_ROUTING_LAYER = metal3
-
What is this report saying about the tile it names?
5_1_grt log
violation type: Horizontal congestion srcs: net:_105_ net:_107_ net:_109_ net:_189_ net:clk net:net52 comment: capacity:7 usage:8 congestion:1 bbox = (16.8000, 16.8000) - (18.9000, 18.9000) on Layer - violation type: Vertical congestion srcs: net:_149_ net:_150_ net:dpath.a_lt_b$in0\[10\] net:clknet_0_clk comment: capacity:5 usage:6 congestion:1 bbox = (21.0000, 21.0000) - (23.1000, 23.1000) on Layer -
One more wire wants to cross the tile than it has tracks for.Hint: Read the comment line as three numbers about one small square of the die.
Global routing divides the die into tiles and counts how many wires want to cross each boundary against how many can. Usage above capacity is the overflow, reported per direction with the nets involved. A little is normal and the detailed router will resolve it; a lot, or a cluster of it in one place, is the congestion that makes a design unroutable.
# give the region room, or the tool more layers to use export CORE_UTILIZATION = 45 export MAX_ROUTING_LAYER = metal6
-
Detailed routing is reporting violations. Should you be worried?
5_2_route log
[INFO DRT-0195] Start 3rd guides tiles iteration. Completing 10% with 31 violations. Completing 20% with 31 violations. Completing 30% with 31 violations. Completing 40% with 31 violations. Completing 50% with 27 violations. Completing 60% with 27 violations. Completing 70% with 27 violations. Completing 80% with 27 violations. Completing 90% with 0 violations. Completing 100% with 0 violations. [INFO DRT-0199] Number of violations = 0.No: the router clears them as it goes, and ended at zero.Hint: Read down the percentages, then read the last line.
The router works in passes, ripping up and rerouting what does not fit, so a count part way through a pass means nothing on its own. What matters is the number at the end of the last iteration. A healthy run of this design also reports violations in its early passes. The number to watch is one that stops falling between iterations.
# nothing to fix here; the line that matters is the last one report_design_area
-
The run finished and reported an area. One line here says the result is a fiction. Which?
6_report log
Design area 691 um^2 59% utilization. [WARNING GUI-0076] QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root' [WARNING GUI-0066] Heat map "IR Drop" has not been populated with data. [WARNING STA-0351] clock '*' not found. [WARNING GUI-0066] Heat map "Routing Congestion" has not been populated with data. Elapsed time: 0:01.06[h:]min:sec. CPU time: user 1.10 sys 0.13 (116%). Peak memory: 180016KB.
The one about a clock, since nothing was timed at all.Hint: Three warnings. Two of them appear in a healthy run of the same design.
A clean run of this design prints the same two heat-map warnings and the same runtime directory line, so neither means anything. The clock line does: the reporting script asked for every clock and there were none, so every timing number in the summary is empty rather than good. This is the last chance to notice, at the end of two hundred lines that all look normal.
# compare against a known-good log rather than reading warnings one by one diff <(grep WARNING good.log) <(grep WARNING this.log)
-
This is a run that worked. What is the tool doing here?
4_1_cts log
[INFO CTS-0010] Clock net "clk" has 35 sinks. [INFO CTS-0008] TritonCTS found 1 clock nets. [INFO CTS-0097] Characterization used 1 buffer(s) types. [INFO CTS-0201] 0 blockages from hard placement blockages and placed macros will be used. [INFO CTS-0027] Generating H-Tree topology for net clk. [INFO CTS-0028] Total number of sinks: 35. [INFO CTS-0090] Sinks will be clustered based on buffer max cap. [INFO CTS-0030] Number of static layers: 0. [INFO CTS-0020] Wire segment unit: 14000 dbu (7 um). [INFO CTS-0023] Original sink region: [(5890, 7170), (63650, 68770)]. [INFO CTS-0024] Normalized sink region: [(0.420714, 0.512143), (4.54643, 4.91214)]. [INFO CTS-0025] Width: 4.1257. [INFO CTS-0026] Height: 4.4000. Level 1 Direction: Vertical Sinks per sub-region: 18 Sub-region size: 4.1257 X 2.2000Splitting the sinks in half, alternating direction, to build a balanced tree.Hint: Read the levels: what is being halved each time, and along which axis?
An H-tree is built by bisecting the region the sinks occupy, vertically then horizontally, until each sub-region holds few enough sinks to drive directly. The numbers to read are the sink count, the region it spans, and where it stopped. Knowing what a healthy log looks like is what makes an unhealthy one obvious.
# nothing to fix; this is the shape a working clock tree leaves behind report_clock_skew
-
Setup repair ran to its limit. What should you conclude?
3_5_place_dp log
[INFO RSZ-0094] Found 49 endpoints with setup violations. [INFO RSZ-0099] Repairing 49 out of 49 (100.00%) violating endpoints... Iter | Removed | Resized | Inserted | Cloned | Pin | Area | WNS | StTNS | EnTNS | Viol | Worst | Buffers | Gates | Buffers | Gates | Swaps | | | | | Endpts | St/EnPt ------------------------------------------------------------------------------------------------------------------------------ 0* | 0 | 0 | 0 | 0 | 0 | +0.0% | -0.123 | -3.7 | -4.9 | 49 | resp_msg[14] 10* | 0 | 3 | 0 | 1 | 5 | +0.6% | -0.129 | -3.9 | -5.2 | 49 | dpath.a_reg.out[2]$_DFFE_PP_/D 20* | 0 | 11 | 0 | 1 | 7 | +1.2% | -0.129 | -3.9 | -5.3 | 49 | dpath.a_reg.out[6]$_DFFE_PP_/D ... final | 0 | 88 | 3 | 1 | 16 | +8.5% | -0.120 | -3.8 | -5.0 | 49 | resp_msg[14] ------------------------------------------------------------------------------------------------------------------------------ [INFO RSZ-0040] Inserted 3 buffers. [INFO RSZ-0051] Resized 88 instances: 88 up, 0 up match, 0 down, 0 VT [INFO RSZ-0043] Swapped pins on 16 instances. [INFO RSZ-0049] Cloned 1 instances. [WARNING RSZ-0062] Unable to repair all setup violations.The target is out of reach, since the area bought no slack.Hint: Read the first data row and the last one, and look at what the area column did in between.
Nearly eight hundred iterations moved the worst slack from -0.123 to -0.120 nanoseconds and spent 8.5 percent more area doing it, with the same 49 endpoints failing at the end as at the start. That is what an unreachable constraint looks like from inside the optimizer. The conversation to have is about the clock period or the architecture, not about optimization effort.
# give it a period the design can hold, then tighten in steps set clk_period 0.46
-
The worst endpoint is resp_msg[14]. What does that name tell you?
3_5_place_dp log
[INFO RSZ-0094] Found 49 endpoints with setup violations. [INFO RSZ-0099] Repairing 49 out of 49 (100.00%) violating endpoints... Iter | Removed | Resized | Inserted | Cloned | Pin | Area | WNS | StTNS | EnTNS | Viol | Worst | Buffers | Gates | Buffers | Gates | Swaps | | | | | Endpts | St/EnPt ------------------------------------------------------------------------------------------------------------------------------ 0* | 0 | 0 | 0 | 0 | 0 | +0.0% | -0.123 | -3.7 | -4.9 | 49 | resp_msg[14] 10* | 0 | 3 | 0 | 1 | 5 | +0.6% | -0.129 | -3.9 | -5.2 | 49 | dpath.a_reg.out[2]$_DFFE_PP_/D 20* | 0 | 11 | 0 | 1 | 7 | +1.2% | -0.129 | -3.9 | -5.3 | 49 | dpath.a_reg.out[6]$_DFFE_PP_/D ... final | 0 | 88 | 3 | 1 | 16 | +8.5% | -0.120 | -3.8 | -5.0 | 49 | resp_msg[14] ------------------------------------------------------------------------------------------------------------------------------ [INFO RSZ-0040] Inserted 3 buffers. [INFO RSZ-0051] Resized 88 instances: 88 up, 0 up match, 0 down, 0 VT [INFO RSZ-0043] Swapped pins on 16 instances. [INFO RSZ-0049] Cloned 1 instances. [WARNING RSZ-0062] Unable to repair all setup violations.The worst path ends at an output port, so the budget is the suspect.Hint: Compare that name with the register names in the rows above it.
Register endpoints carry the flop's name and a pin, as the rows above do. A bare port name means the path is checked against an output delay instead, which is a number someone chose. Before optimizing the logic it is worth asking whether the block was given a fair share of the period.
# check what the interface was promised before reoptimizing the logic report_checks -to [get_ports resp_msg*] -path_delay max
-
The setup check is clean and repair found nothing. What would you verify?
3_5_place_dp log
========================================================================== Floorplan check_setup -------------------------------------------------------------------------- number instances in verilog is 521 [INFO IFP-0107] Defining die area using utilization: 55.00% and aspect ratio: 1. [WARNING IFP-0028] Core area lower left (1.000, 1.000) snapped to (1.140, 1.400). [INFO IFP-0001] Added 24 rows of 182 site FreePDK45_38x28_10R_NP_162NW_34O. ... [WARNING EST-0027] no estimated parasitics. Using wire load models. [INFO RSZ-0100] Repair move sequence: UnbufferMove SizeUpMove SwapPinsMove [INFO RSZ-0098] No setup violations found [INFO RSZ-0505] Runtime: 0.03sWhether an exception has removed the paths from the analysis.Hint: Every earlier sign of an untimed design is absent here. What else could empty the reports?
This run carries a false path from the clock to itself, which removes every register-to-register path in the design. Unlike an undefined clock, it leaves no unclocked pins and no unconstrained endpoints, so the checks that catch the other mistakes say nothing. Counting the paths that were timed, or reporting the exceptions, is what finds it.
report_checks -path_delay max -group_path_count 1000 | grep -c Startpoint report_exceptions
-
This run closed with room to spare. What did the spare room cost?
6_report log
[INFO IFP-0100] Die BBox: ( 0.000 0.000 ) ( 93.045 93.045 ) um [INFO IFP-0101] Core BBox: ( 1.140 1.400 ) ( 91.960 91.000 ) um [INFO IFP-0102] Core area: 8137.472 um^2 [INFO IFP-0103] Total instances area: 663.138 um^2 [INFO IFP-0104] Effective utilization: 0.081 [INFO IFP-0105] Number of instances: 521 ... Total wire length = 6098 um. Design area 767 um^2 9% utilization.Longer wires, and the buffers repair added to drive them.Hint: Compare the wire length and the area with a run of the same design at 57 percent.
The same netlist at 57 percent utilization routes 3605 micrometres of wire and finishes at 716 square micrometres of cells. Here the core is seven times larger, the wire length is 6098, and the cell area has grown to 767 because timing repair had to drive those longer wires. Too much room is a real cost, not just a wasted one.
export CORE_UTILIZATION = 55
-
Pin placement stopped. What was it told to do?
3_2_place_iop log
Found 0 macro blocks. Using 2 tracks default min distance between IO pins. [ERROR PPL-0051] Layer metalX not found. Error: io_placement.tcl, 21 PPL-0051 Elapsed time: 0:00.21[h:]min:sec. CPU time: user 0.17 sys 0.04 (100%). Peak memory: 113920KB. make[1]: *** [Makefile:460: do-3_2_place_iop] Error 1 make: *** [Makefile:460: results/nangate45/gcd/bad_pins/3_2_place_iop.odb] Error 2
Place the ports on layers the technology does not have.Hint: The command is printed above the error, with both of its arguments.
The port placer is told which layers to use for horizontal and vertical pins, and it checks the names against the technology. The choice matters beyond spelling: a layer too low makes the pins hard for the router to reach, and one too high wastes the upper stack. Both names here are simply wrong, which the tool says plainly.
export IO_PLACER_H = metal3 export IO_PLACER_V = metal2
-
The spacing between clock buffers was set to one micrometre. What did that do?
4_1_cts log
clock_tree_synthesis -sink_clustering_enable -repair_clock_nets -distance_between_buffers 1 ... [INFO CTS-0021] Distance between buffers: 0 units (1 um). [INFO CTS-0035] Number of sinks covered: 35. [INFO CTS-0018] Created 7 clock buffers. [INFO CTS-0012] Minimum number of buffers in the clock path: 3. [INFO CTS-0013] Maximum number of buffers in the clock path: 3. [INFO CTS-0015] Created 7 clock nets.More buffers and a deeper tree, on a block too small to need either.Hint: Compare seven buffers and a minimum depth of three against five and two.
The default run of this design builds five buffers with a minimum depth of two. Forcing one every micrometre gives seven and a depth of three, and the design area grows from 716 to 764 square micrometres. Depth costs variation and power. The knob is there for large blocks with long clock runs, and it does harm on a small one.
# leave the spacing to the tool unless the tree is genuinely long export CTS_BUF_DISTANCE = 60
-
The error is at the end. Which line above it is the cause?
1_2_yosys log
14. Executing INSBUF pass (insert buffer cells for connected wires). 15. Executing CHECK pass (checking for obvious problems). Warning: multiple conflicting drivers for gcd.\resp_rdy: port Z[0] of cell $auto$insbuf.cc:97:execute$2712 (BUF_X1) module input resp_rdy[0] 16. Printing statistics. 17. Executing CHECK pass (checking for obvious problems). ERROR: Found 1 problems in 'check -assert'.The warning, which says one signal has two drivers.Hint: The error says a check failed. The check printed what it found one step earlier.
A net with two drivers has no defined value, so the check refuses to pass the netlist on. The error line itself says only that a check failed; the detail is in the warning above, which names the signal and both of the things driving it. One of them here is a module input, which usually means an output was assigned a name that already belongs to a port.
// drive each net from exactly one place assign clash = req_val;
-
Global placement printed this, before any routing ran. What is it?
3_1_place_gp log
[INFO GPL-0041] Total routing overflow: 0.0000 [INFO GPL-0042] Number of overflowed tiles: 0 (0.00%) [INFO GPL-0043] Average top 0.5% routing congestion: 0.7465 [INFO GPL-0044] Average top 1.0% routing congestion: 0.7361 [INFO GPL-0045] Average top 2.0% routing congestion: 0.7240 [INFO GPL-0046] Average top 5.0% routing congestion: 0.6931 [INFO GPL-0047] Routability iteration weighted routing congestion: 0.7413
The placer's own estimate of how routable its placement is.Hint: Ask how a placer could know anything about congestion at all.
A placer in routability mode runs a quick trial route and reads the overflow back, which is how it knows to spread cells apart before the real router ever starts. The averages of the worst tiles matter far more than the overall figure: congestion is local, and a design with an average of 0.72 and a handful of tiles at 1.0 is the one that fails.
# if the top percentiles are near or above 1, spread the design out export PLACE_DENSITY_LB_ADDON = 0.30
-
Detailed routing on a larger design. Is this going to finish?
5_2_route log
[INFO DRT-0195] Start 0th optimization iteration. [INFO DRT-0199] Number of violations = 5434. [INFO DRT-0195] Start 1st optimization iteration. [INFO DRT-0199] Number of violations = 2304. [INFO DRT-0195] Start 2nd optimization iteration. [INFO DRT-0199] Number of violations = 1925. [INFO DRT-0195] Start 3rd optimization iteration. [INFO DRT-0199] Number of violations = 100. [INFO DRT-0195] Start 4th guides tiles iteration. [INFO DRT-0199] Number of violations = 0.
Yes: each pass clears most of what the one before it left.Hint: Look at the ratio between one pass and the next, not at the first number.
The shape is what matters. Five thousand becomes two thousand, then two thousand becomes a hundred, and the last pass finishes clean, which is a router that is winning. The pass to worry about is one that returns almost the same number as the pass before it, over and over: that is a design the router cannot fix by rerouting, and it needs the placement or the floorplan changed instead.
# nothing here; read the trajectory before reacting to the first number grep "Number of violations" 5_2_route.log
-
The grid was built, and then this. What would you check first?
2_4_floorplan_pdn log
[INFO PDN-0500] Runtime: 0.00s Design area 676 um^2 58% utilization. write_db ./results/nangate45/gcd/dfull/2_4_floorplan_pdn.odb Error: close for ./results/nangate45/gcd/dfull/2_4_floorplan_pdn.odb failed: basic_ios::clear: iostream error Error: pdn.tcl, 24 basic_ios::clear: iostream error Elapsed time: 0:00.38[h:]min:sec. CPU time: user 0.33 sys 0.05 (98%). Peak memory: 117448KB. make[1]: *** [Makefile:429: do-2_4_floorplan_pdn] Error 1 make: *** [Makefile:429: results/nangate45/gcd/dfull/2_4_floorplan_pdn.odb] Error 2
Whether there is room on the disk to write the file.Hint: Read what the tool was doing when it failed, not what it was doing before.
The grid was inserted and the area reported, so the work succeeded. The failure is in closing the file it was written to, and a stream error on close is what a full disk looks like from inside a program. Nothing in the message says disk, which is exactly why this one is worth recognizing: check the filesystem before you doubt the design.
df -h . make clean_all # or point the flow somewhere with room
-
Put these messages in the order a run prints them.
- [INFO ODB-0227] LEF file: ... created 22 layers, 27 vias
- [INFO IFP-0001] Added 24 rows of 182 site FreePDK45
- [INFO CTS-0008] TritonCTS found 1 clock nets.
- [INFO DRT-0199] Number of violations = 0.
- [INFO RCX-0045] Extract 648 nets, 2366 rsegs
Hint: The three letters before the number name the tool that printed it.
The prefix is the module: reading the technology, initializing the floorplan, building the clock tree, detailed routing, and extraction. Knowing them turns a wall of output into a map, and it is how you find the right log without reading any of them. The full list is in the tool's documentation, and the codes are stable across versions.
-
A design closes with suspiciously good timing. Put these checks in the order that finds the cause fastest.
- read the constraint log for a clock or port that was not found
- read the floorplan check for unclocked pins and unconstrained endpoints
- count how many paths the timer actually reported
- report the exceptions that remove paths from the analysis
Hint: Each step catches a cause the step before it cannot see.
The first two are free and catch the common cases: a clock created on nothing, or ports with no delay. Counting the paths catches a design that is timed but barely. Exceptions come last because they take the most reading, and they are the only thing that catches a false path wide enough to empty the analysis while every check stays clean.
-
Hold violations appear everywhere after the clock tree. Put these in the order you would work through them.
- check the hold uncertainty in the constraints
- check the skew the clock tree actually achieved
- confirm setup is closed, since hold fixes will slow the paths
- let repair insert hold buffers
Hint: Rule out what you wrote before you rule out what the tool did.
Everywhere at once means a common cause, and the cheapest common cause is a number someone typed. Skew comes next, since a badly balanced tree creates hold failures across a whole region. Setup has to be settled before hold, because the buffers hold repair inserts add delay. Only then is inserting buffers the right move rather than a way to hide something.
-
The router was making progress and then stopped. What happened?
5_2_route log
[INFO DRT-0195] Start 0th optimization iteration. Completing 20% with 0 violations. elapsed time = 00:00:01, memory = 278.67 (MB). Completing 50% with 25 violations. elapsed time = 00:00:02, memory = 302.66 (MB). Completing 70% with 45 violations. elapsed time = 00:00:03, memory = 324.15 (MB). Completing 100% with 67 violations. elapsed time = 00:00:04, memory = 342.52 (MB). Elapsed time: 0:05.62[h:]min:sec. CPU time: user 15.44 sys 0.14 (277%). Peak memory: 350108KB. make[1]: *** [Makefile:552: do-5_2_route] Error 247 make: *** [Makefile:552: results/nangate45/gcd/oom/5_2_route.odb] Error 2The machine killed it for taking too much memory.Hint: One column climbs on every line. Read that one, then read the exit code.
There is no tool error here at all: the last line the tool wrote was a normal progress line at 342 megabytes, having started the stage at 267. An exit code in the 240s with no message is the shell reporting that something outside the tool ended it, and the growing memory column says what. On a shared machine, look at the job's memory limit before you look at the design.
# give the job room, or ask the router for fewer threads make DESIGN_CONFIG=... NUM_CORES=4
-
The design-rule count is zero. What has that proved?
6_drc log
$ cat reports/sky130hd/gcd/6_drc_count.rpt 0 $ head reports/sky130hd/gcd/6_drc.lyrdb <report-database> <description>SKY130 DRC runset</description> <original-file/> <generator>drc: script='/OpenROAD-flow-scripts/flow/platforms/sky130hd/drc/sky130hd.lydrc'</generator> <top-cell>gcd</top-cell> <tags> </tags> <categories> <category> <name>li.1</name> <description>li.1 : min. li width : 0.17um</description> <categories> </categories>
That this deck's rules found nothing, which is narrower than clean.Hint: Read what the report says about itself before reading its result.
The report names the deck it came from and lists the rules it knows, each with its own description. An open deck implements a subset of what a foundry's sign-off deck checks, so a zero means only that the subset passed. The number itself is counted by matching markers in the report database, which is why the count file and the database must be read together.
# know which rules your deck implements before trusting the count grep -c "<category>" 6_drc.lyrdb
-
Did layout versus schematic find a mismatch?
6_lvs log
KLayout 0.30.7 ERROR: In /OpenROAD-flow-scripts/flow/platforms/sky130hd/lvs/sky130hd.lylvs: Can't find a value for a R, C or L device in /OpenROAD-flow-scripts/flow/objects/sky130hd/gcd/sky_signoff/6_final_concat.cdl, line 5740 in Netlist::read ERROR: RuntimeError: Can't find a value for a R, C or L device in /OpenROAD-flow-scripts/flow/objects/sky130hd/gcd/sky_signoff/6_final_concat.cdl, line 5740 in Netlist::read in Executable::execute
No: it stopped while reading the netlist, before comparing.Hint: Ask what stage of the check this message comes from.
The comparison never started. The reader hit a passive device with no value on it and gave up, which usually means the netlist handed to the check was assembled wrongly rather than that the design is wrong. A check that did not run is not a check that passed, and it is worth being strict about the difference: the line to look at is the one the error names.
sed -n '5740p' 6_final_concat.cdl
-
The same design on the default grid drops 0.38 percent. What does this run tell you?
6_report log
[INFO PSM-0040] All shapes on net VDD are connected. ########## IR report ################# Net : VDD Corner : default Total power : 2.61e-03 W Supply voltage : 1.10e+00 V Worstcase voltage: 1.09e+00 V Average voltage : 1.09e+00 V Average IR drop : 8.77e-03 V Worstcase IR drop: 1.25e-02 V Percentage drop : 1.14 % ######################################
The grid is carrying the same current through less metal.Hint: The power is the same in both runs. Only one thing changed.
Total power is 2.61 milliwatts here against 2.62 in the default run, so the design is doing the same work. The straps were narrowed and spread out, and the drop tripled. A percentage of a percent is still healthy, since limits are usually a few percent, but the trend is what a grid review watches: the number means nothing without the grid and the activity that produced it.
# widen or tighten the straps until the drop fits the budget add_pdn_stripe -layer metal4 -width 1.4 -pitch 6.5 -offset 0