Goal
Never discover after an hours-long run that a SKIP_* flag or a helper default
routed around the exact code path you were trying to exercise. Spend a few
minutes up front proving the run will hit it.
The core move: mentally dry-run the flow TCL
ORFS flow scripts read only a handful of env vars — stepping through
global_route.tcl / util.tcl (or the relevant stage script) by hand is quick.
Trace which vars gate your target code path, plug in your intended settings, and
predict the exact command the run will emit and whether your path executes.
If the prediction is wrong, adjust the invocation before launching. This is
minutes of reading that saves hours of runtime.
Know how each var reaches the tool — cmdline vs export
This is the subtlety that bites: a make command-line variable does not
reach openroad's process env unless the Makefile explicitly exports it (make
does not auto-export cmdline vars).
- A var the stage's
args.mkmarksexportdoes propagate when you override it on the make command line (e.g.SKIP_INCREMENTAL_REPAIR=...). - A var that is only read from the TCL's
::env(...)but is not exported by the flow will not see your make-cmdline override — you must pass it as a real exported ENV var.
Worked example of the failure mode: a repair helper selects -setup vs -hold
from ::env(REPAIR_SETUP_ONLY), defaulting to setup-only unless it equals 0.
If that var is neither in the args.mk nor blanket-exported, a make-cmdline
REPAIR_SETUP_ONLY=0 never reaches openroad → the run silently does setup-only
and tests nothing about hold. The fix is to export it as an ENV var, not pass it
on the make line.
The pre-flight checklist
- Dump the stage's effective vars. Grep the stage
*.args.mk(e.g.<stage>.args.mk) for the gating vars —SKIP_*,*_EFFORT,*_SLACK_MARGIN, setup/hold selectors — and note your command-line overrides, remembering cmdline beats?=/exportonly for exported vars. - Read the flow TCL to see how those vars gate your target. e.g.
global_route.tcl'sif { !$SKIP_INCREMENTAL_REPAIR } { ... repair_timing_helper }, and the helper's-setup/-hold/-effortlogic. Write down the exact command your run should emit (the flow echoes it back). - Prove the path fires. Once running, check the log for the invocation and
its markers before trusting the result (e.g.
repair_timing, the RSZ hold- endpoint / hold-buffer messages,Took N seconds: <command>). If a phase is absent, a flag routed around it — stop and fix the invocation. - Only then commit to the hours-long run.
Not every log tag matches the stage name
OpenROAD passes call into each other's code, so a stage log naturally interleaves
message tags from other modules — e.g. a global-route (grt) run emits
detailed-router (DRT-*) messages during pin_access, which is drt code that
grt pulls on as slow prep before repair_timing. Seeing another module's tag
is not evidence of a mis-run stage; check the actual command sequence, not the
tag prefixes.
Is there anything for the run to optimize?
An optimization stage measures nothing on a design that already meets its
constraints, and it will say so in the most misleading way available: clean
zeros, no violations, no error. Before a long run whose point is a QoR effect,
check that the baseline actually has a problem to solve — report_wns /
report_tns on the input, and stop if TNS is 0.
ORFS designs are calibrated for this. They sit a percent or two past closure — asap7/aes −4.78ps on a 380ps period (−1.3%), asap7/riscv32i −18.9ps on 950ps (−2.0%) — which is what makes them useful: there is work to do, and the design is not hopeless.
That calibration is fragile, and anything that makes the design faster
silently destroys it. A faster cell library at an unchanged period is the easy
way to do this by accident: asap7/aes with the full RVT/LVT/SLVT ladder at aes's
own 380ps closes outright (+0.09ps WNS, 0.0 TNS) and any repair-stage
measurement on it is vacuous. This is why ORFS's own aes_lvt retimes its clock
to 360ps rather than inheriting aes's 380ps.
So if you introduce a library variant, retune the period and measure where it landed rather than assuming. Bracketing costs one short run per point:
304ps +0.02ps (+0.01% of period) closes -- useless
285ps -10.35ps (-3.63% of period) chosen
266ps -28.37ps (-10.67% of period) too far gone
Pairs with repair-timing-grt (a skip-repair grt measures nothing about repair)
and byo-openroad.