Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request simplifies and standardizes parasitics estimation across various flow scripts by replacing explicit estimation flags (such as -placement or -global_routing) with a bare estimate_parasitics call, allowing OpenROAD to automatically determine the correct source based on the design's state. It also introduces the final_extracts_parasitics helper function, updates documentation, and extends the SKIP_DETAILED_ROUTE variable to the generate_abstract stage. There are no review comments, so I have no feedback to provide.
The flow decided which parasitics to time with in four places, open.tcl, generate_abstract.tcl, write_endpoint_slack and final_outputs.tcl, from the stage number, grt::have_routes and whether a .spef file exists. A file on disk says nothing about whether it belongs to the design being timed: re-running a flow from place or global route leaves the previous final's SPEF in the results directory. estimate_parasitics without a flag now picks the source itself: global routes when there are any, else placement, nothing after read_spef. The stage scripts call it bare, under log_cmd, where they want to pay for an estimate. 6_final is timed with 6_final.spef when the final stage extracted it, which final_extracts_parasitics says from RCX_RULES and SKIP_DETAILED_ROUTE; read_spef fails if the file is missing. A placed design is timed with parasitics, a design before placement without. Changes in behavior: - With RCX configured, a missing 6_final.spef fails open and generate_abstract instead of falling back to an estimate. - A global route that is congested and was not accepted fails estimate_parasitics instead of timing without parasitics; open with GUI_TIMING=0 to look at it. A failed route written with GENERATE_ARTIFACTS_ON_FAILURE gets no endpoint slack snapshot. - generate_abstract from global route or later is timed with global route parasitics instead of placement parasitics. - The endpoint slack snapshot records where OpenROAD's parasitics came from: 6_final says spef instead of rcx, and 3_1_place_gp_skip_io with unplaced pins says none instead of placement. SKIP_DETAILED_ROUTE reaches generate_abstract, which needs it to know whether 6_final has a SPEF. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
410dfb2 to
2447d20
Compare
🔍 QoR checkMetrics reflect the PR merge build — i.e. what will land on the target branch. Commit 62 design(s) checked — 0 with regression(s), 1 without a comparable baseline. |
generate_abstract.tcl conflicted with The-OpenROAD-Project#4688 (695436e), which this change supersedes: the flagless estimate_parasitics times an abstract from global route on with the route's parasitics, and the SPEF is read only where final_extracts_parasitics says one was made. Kept this branch's side. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
@eder-matheus 🥺 ? tools/OpenROAD must be bumped, which I will let someone else do. If you approve + automerge, it will go in when pr-merge goes green. |
|
@maliberty @eder-matheus pr-merge is red, but that's just a QoR problem that will fix itself when any ORFS pr is merged. So... this PR is as good as any. Merge? |
| if { $stem == "6_final" && [final_extracts_parasitics] } { | ||
| log_cmd read_spef $::env(RESULTS_DIR)/6_final.spef | ||
| } | ||
| if { [grt::design_is_placed] } { | ||
| log_cmd estimate_parasitics | ||
| } |
There was a problem hiding this comment.
why not an elseif - is there a case where you want to both read_spef and estimate parasitics?
There was a problem hiding this comment.
No case wants both. It is an elseif now, in orfs_load_parasitics in util.tcl (92bda58); the two ifs only worked because estimate_parasitics does nothing after read_spef.
| } elseif { $design_stage >= 3 } { | ||
| log_cmd estimate_parasitics -placement | ||
| } | ||
| if { [grt::design_is_placed] } { |
There was a problem hiding this comment.
No case wants both. It is an elseif now, in orfs_load_parasitics in util.tcl (92bda58); the two ifs only worked because estimate_parasitics does nothing after read_spef.
|
Codex (trimmed) The other findings:
|
|
needs a merge of master to pick up a later OR version with: That commit includes OR #11788 (merge commit 99bd6268d8, "est-parasitics-auto"). |
The endpoint-slack table left out the SKIP_DETAILED_ROUTE=1 fallback that final_extracts_parasitics takes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
generate_abstract.tcl reads 6_final.spef when final extracts parasitics, so the target lists it with the other 6_final files. The file is a result of 6_report like 6_final.def; without RCX_RULES, or with detailed route skipped, no SPEF is written and make goes on without it, so the graph stays the same for every design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
open.tcl, generate_abstract.tcl and write_endpoint_slack each had the same two tests: read 6_final.spef when final extracts parasitics, and estimate when the design is placed. orfs_load_parasitics in util.tcl now holds them, as one if/elseif: a design timed with the extracted SPEF is never also estimated. orfs_load_parasitics returns where the parasitics came from, and the endpoint-slack snapshot records that, so the label always describes the parasitics the snapshot was timed with. est::parasitics_source on its own reported the last estimate in the process, which is stale for a step that does not estimate. final_outputs.tcl loads its parasitics itself, by extraction or by an estimate, and now tells write_endpoint_slack not to load them again. Without RCX_RULES, 6_final was estimated twice in a row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
Merged master, which brings OpenROAD 98c6045c, which includes #11788. New commits, one per finding:
gcd asap7 with this change against without it: |
The flow decides which parasitics to time with in four places:
open.tcl,generate_abstract.tcl,write_endpoint_slackandfinal_outputs.tcl. Each decides from the stage number,grt::have_routesand whether a.speffile exists. Those rules are easy to get wrong. #4688 fixes one copy: an abstract written from global route was timed with placement parasitics, 6.9 ns instead of 1.8 ns on one arc.Gemini Code Assist's review of #4688 is a concrete example. It suggested reading
$stem.speffrom stage 5 on whenever the file exists (comment). It reads as a sensible improvement, and it's wrong:RESULTS_DIR. The re-run stage's timing would silently use parasitics from a different netlist, and nothing in the log would show it.The rules are subtle enough that an AI reviewer, given the code, proposed a change that turns a loud failure into a silent wrong number. A reviewer reading only the diff, human or bot, couldn't have caught it either: the decision is spread over four scripts and depends on which files a previous run left behind. So the rules belong somewhere they can't be gotten wrong.
Whether a file is on disk is not a valid test, and a stage number is a second copy of a fact OpenROAD already has. So:
estimate_parasiticsuses global routes if they exist, otherwise placement. It fails loudly on an unplaced design, zero wire RC, or a congested route that wasn't accepted, and does nothing onceread_spefhas run.log_cmd estimate_parasiticswherever it wants to pay for an estimate (the log shows the time), and an unconditionalread_spefexactly where its configuration says a SPEF was made.final_extracts_parasiticssays so fromRCX_RULESandSKIP_DETAILED_ROUTE. A missing SPEF fails loudly, and a stale one is never read.On gcd (asap7 and nangate45), the flow with this change and the OpenROAD one is byte-identical to today's at every stage: the
.odbfiles from place through final, the abstract's.liband.lef, and6_final.spefapart from its*DATEline. What changes is what happens to a SPEF that is missing or doesn't belong to the design:generate_abstracton gcd's results6_final, SPEF missingcannot read file .../6_final.spef6_final, detailed route skipped, leftover SPEF6_final, extracted SPEFChanges in behaviour:
6_final.speffailsopenandgenerate_abstractinstead of falling back to an estimate.estimate_parasiticsinstead of being timed without parasitics. To look at one, open it withGUI_TIMING=0. A failed route written withGENERATE_ARTIFACTS_ON_FAILUREgets no endpoint-slack snapshot.generate_abstractfrom global route or later is timed with global-route parasitics instead of placement parasitics. This supersedes generate_abstract: time a global-route abstract with the route's parasitics #4688's change.6_finalsaysspefinstead ofrcx, and3_1_place_gp_skip_iowith unplaced pins saysnoneinstead ofplacement.SKIP_DETAILED_ROUTEnow reachesgenerate_abstract, which needs it to know whether6_finalhas a SPEF.Integration test: The-OpenROAD-Project/bazel-orfs#1284, which runs ORFS's
generate_abstract.tclon copies of gcd's results (missing, leftover and extracted SPEF, and an abstract from global route) on asap7 and nangate45.🤖 Generated with Claude Code