rsz: Prevent hold repair from buffering internal output arcs#10236
Conversation
ASAP7 full-adder cells expose output-to-output timing arcs such as CON -> SN. RepairHold was treating every timing-graph fanout from a driver vertex as a physical net load, so an internal output pin could be passed to insertBufferBeforeLoads for the driver's net. OpenDB correctly rejects that with ODB-1200 because the output pin is not connected to the net being split. The fix filters internal output pins while preserving top-level output ports as valid loads. A reduced netlist regression exercises the failing post-CTS hold repair path without relying on a saved ODB snapshot. Constraint: ASAP7 liberty includes output-to-output timing groups that OpenSTA represents as graph edges Rejected: Pass loads_on_diff_nets=true | would mask invalid load collection and let repair_hold split unrelated nets Rejected: Saved ODB regression | too brittle for OpenROAD architecture refactors Confidence: high Scope-risk: narrow Directive: Do not treat timing graph fanout as physical net loads without direction/connectivity intent checks Tested: clang-format on src/rsz/src/RepairHold.cc Tested: clang-tidy src/rsz/src/RepairHold.cc -p build --quiet Tested: cmake --build build --target openroad -j 8 Tested: ctest --test-dir build -R 'rsz\.repair_hold_multi_output_load\.tcl$' --output-on-failure -j 1 Tested: ctest --test-dir build -R 'rsz\.(gcd_resize|repair_hold.*)\.tcl$' --output-on-failure -j 4 Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
There was a problem hiding this comment.
Code Review
This pull request addresses a bug in hold timing repair where internal output pins of multi-output cells were incorrectly treated as load pins. The changes introduce filtering for these pins, add safety checks for empty load sets, and simplify the driver net lookup process. A new regression test is provided to ensure correct behavior. The review feedback suggests a more robust pin filtering condition—checking for the absence of an input direction rather than the presence of an output direction—to avoid incorrectly skipping valid inout pins.
| if (network_->direction(load_pin)->isAnyOutput() | ||
| && !network_->isTopLevelPort(load_pin)) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
The current check using isAnyOutput() will filter out internal inout pins, which are valid load pins. To correctly filter only pure output pins (which are the ones causing the issue with internal timing arcs), it is safer to check if the pin lacks an input component.
| if (network_->direction(load_pin)->isAnyOutput() | |
| && !network_->isTopLevelPort(load_pin)) { | |
| continue; | |
| } | |
| if (!network_->isTopLevelPort(load_pin) | |
| && !network_->direction(load_pin)->isAnyInput()) { | |
| continue; | |
| } |
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
This is not a good test. It is not minimal in data size nor in command scope (running a complete flow from .v will be susceptible to changes in all the previous commands results).
There was a problem hiding this comment.
This concern is still not full addressed. It depends on initialize_floorplan and detailed_placement. It would be more natural to have an input def file that is already placed and drop the .v. Look at most of the other tests.
There was a problem hiding this comment.
I assume this is AI generated so perhaps some guidance in agents.md would be helpful.
There was a problem hiding this comment.
Reduced the new test case again.
Add OR & ORFS PRs.
- For better OR test case creation: doc: Add a new guide for creating issue reproduction test case #10269
- Enable OR
AGENTS.mddiscovery when the AI agent is executed from the ORFS root: doc: AddAGENTS.mdOpenROAD-flow-scripts#4193
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
| #include "sta/Graph.hh" | ||
| #include "sta/GraphClass.hh" | ||
| #include "sta/GraphDelayCalc.hh" | ||
| #include "sta/InputDrive.hh" |
| } else { | ||
| drvr_dbnet = static_cast<odb::dbITerm*>(drvr_db_pin)->getNet(); | ||
| } | ||
| odb::dbNet* drvr_dbnet = db_network_->findFlatDbNet(drvr_pin); |
| if (network_->direction(load_pin)->isAnyOutput() | ||
| && !network_->isTopLevelPort(load_pin)) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
This is the fix.
Output pin cannot be a load pin.
There was a problem hiding this comment.
Reduced the new test case again.
Add OR & ORFS PRs.
- For better OR test case creation: doc: Add a new guide for creating issue reproduction test case #10269
- Enable OR
AGENTS.mddiscovery when the AI agent is executed from the ORFS root: doc: AddAGENTS.mdOpenROAD-flow-scripts#4193
Fixes #10213
Summary
asap7full adder liberty cell `` has a weirdoutput-to-outputtiming arc..lib, the timing edge traversal to find load cell instances with a driver pin picked a wrong load instance, which producedODB-1200error.RepairHoldload collection before callinginsertBufferBeforeLoadsto avoid detecting wrong load instances.Root Cause
The failing ASAP7 full-adder instance has multiple output pins. The target repair net is driven by one output pin, but the Liberty timing graph also exposes an output-to-output arc from that driver output to another output pin on the same instance, for example
CON -> SN.Before this fix, hold repair effectively treated every timing-graph fanout as a physical net load:
That is wrong for an internal output pin reached through an output-to-output timing arc. In the crash case,
SNis not connected to the target driver net, so OpenDB rejects buffering it as a load on that net and reportsODB-1200.Fix
Filter internal output pins while collecting hold-repair loads. Top-level output ports remain valid loads, but output pins on internal instances are not load pins for the target net.
sta::Slack fanout_hold_slack = sta_->slack(fanout, min_); sta::Pin* load_pin = fanout->pin(); + if (load_pin == nullptr) { + continue; + } + if (network_->direction(load_pin)->isAnyOutput() + && !network_->isTopLevelPort(load_pin)) { + continue; + } if (fanout_hold_slack < hold_margin) { load_pins.push_back(load_pin); Slacks fanout_slacks;Testing
clang-format -i src/rsz/src/RepairHold.ccclang-tidy src/rsz/src/RepairHold.cc -p build --quietcmake --build build --target openroad -j 8ctest --test-dir build -R 'rsz\.repair_hold_multi_output_load\.tcl$' --output-on-failure -j 1ctest --test-dir build -R 'rsz\.(gcd_resize|repair_hold.*)\.tcl$' --output-on-failure -j 4