Skip to content

dbSta: keep top-level supply ports visible in pin iterator (#10414) - #10723

Open
saurav-fermions wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
Fermions-ASI:fix/10414
Open

dbSta: keep top-level supply ports visible in pin iterator (#10414)#10723
saurav-fermions wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
Fermions-ASI:fix/10414

Conversation

@saurav-fermions

Copy link
Copy Markdown
Contributor

Summary

write_verilog -include_pwr_gnd stopped emitting assign <port> = <net>; for top-level supply ports wired to an internal supply net of a different name (e.g. vccd1/vccd2 -> vdpwr), breaking LVS. This keeps top-level supply ports visible in the pin iterator so the assigns are restored.

Type of Change

  • Bug fix

Impact

Power/ground port connections reappear in written Verilog; fixes the LVS breakage.

Verification

  • Local build succeeds.
  • Relevant tests pass (rebuilt from source): ctest -R '^dbSta\.' 71/71.
  • Code follows the repository's formatting guidelines.
  • I have signed my commits (DCO).

Related Issues

Fixes #10414


Developed with SAIGE, Fermions' autonomous RTL/EDA debugging agent; root-caused, tested, and signed off by the submitter (@saurav-fermions).

@saurav-fermions
saurav-fermions requested a review from a team as a code owner June 21, 2026 05:16

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies DbInstancePinIterator::hasNext() in dbNetwork.cc to retain power and ground supply boundary terms (BTerms) for the top-level block. This ensures top-level ports remain visible to consumers like write_verilog, which requires them to emit the correct assign statements connecting ports to internal supply nets with different names, fixing issue #10414. Additionally, a new test case write_verilog10 has been added to verify this fix. There are no review comments, so I have no feedback to provide.

@maliberty

Copy link
Copy Markdown
Member

Needs

src/dbSta/test/BUILD:290: unsorted-dict-items: Dictionary items are out of their lexicographical order. 

fixed

saurav-fermions added a commit to Fermions-ASI/OpenROAD that referenced this pull request Jun 24, 2026
Move the write_verilog10 file-deps entry after write_verilog1 to satisfy
buildifier's unsorted-dict-items check (BUILD:290).

Addresses @maliberty review on The-OpenROAD-Project#10723.

Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
@saurav-fermions

Copy link
Copy Markdown
Contributor Author

Fixed — moved the write_verilog10 entry after write_verilog1 so the dict is in lexicographical order. The write_verilog* tests still pass (11/11).

@maliberty
maliberty requested a review from dsengupta0628 June 24, 2026 15:02

@dsengupta0628 dsengupta0628 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is partial revert of the change by @gadfort #8957

Bug Peter's PR fixed: power/ground nets connected to leaf instances whose LEF does not mark pins as POWER/GROUND (real case: COVER BUMP cells with INOUT pins). OpenSTA then builds a timing graph over those supply nets --> memory blows. Fix: added isPGSupply() and filtered supply terms out of 4 iterators:

  1. DbInstancePinIterator - top branch (BTerms)
  2. DbInstancePinIterator - leaf branch (ITerms)
  3. DbNetPinIterator
  4. DbNetTermIterator

What PR #10723 reverts
Only 1 from above--> the top-level BTerm branch. Other 3 filters stay.
The memory blowup likely came from leaf instance ITerms (COVER BUMP cells) : that path (2, 3) stays filtered. This PR only re-exposes top-level primary I/O ports, a different code path.

Now exposing top supply BTerms could let OpenSTA add graph vertices/edges at the top boundary for supply nets. But the heavy blowup in Peter's case was leaf-instance traversal, not top ports so maybe unlikely to reproduce #8957's symptom. I would still prefer this to be verified.

Another concern. After this PR,

  • DbInstancePinIterator (top branch) --> supply BTerm visible
  • DbNetTermIterator::next() + DbNetPinIterator --> supply BTerm/ITerm still filtered

Same supply BTerm now appears when you walk the top instance's pins but is hidden when you walk its net's terminals. Any consumer that cross-references pins to net-terms assumes symmetry --> could mismatch.
write_verilog likely fine (it walks instance pins to emit assigns), but please confirm no other consumer of DbInstancePinIterator (e.g. graph builder, sta sdc, parasitics) chokes on supply ports reappearing.

@saurav-fermions

Copy link
Copy Markdown
Contributor Author

@dsengupta0628 thanks for the careful analysis — you've characterized it exactly right.

On #8957 not regressing: agreed. Peter's blow-up came from leaf-instance ITerm traversal (the COVER-BUMP cells with unmarked INOUT pins). This PR only re-exposes the top-level primary-I/O BTerm branch of DbInstancePinIterator; the three filters that guard the heavy path — the leaf ITerm branch, DbNetPinIterator, and DbNetTermIterator — all stay in place, so the leaf-instance supply-net traversal that caused the memory growth is unchanged.

On the asymmetry (top instance-pin walk shows a supply BTerm; the net-terminal walk still hides it): that's a real and deliberate observation. The motivation is #10414write_verilog walks the top instance's pins to emit the assign <port> = <net>; aliases that tie a power/ground port to an internal supply net of a different name; filtering the top BTerms drops those and breaks LVS. write_verilog is symmetric-safe here because it consumes the pin walk, not a pin↔net-term cross-reference.

On the other consumers you flagged (graph builder / SDC / parasitics): the dbSta regression suite and the write_verilog* tests (11/11) pass with this change, and the timing-graph builder keys off net connectivity (still filtered) rather than the top-port pin walk. That said, I take your point that the asymmetry is an implicit invariant; if you'd prefer, I can either (a) add an assertion/test that specifically cross-checks top-port pins vs net-terms, or (b) make the exposure symmetric by also surfacing top-level supply BTerms in DbNetTermIterator/DbNetPinIterator (scoped to the top block only, so leaf ITerms stay filtered and #8957 is unaffected). Happy to go whichever way you and @maliberty prefer.

@dsengupta0628

Copy link
Copy Markdown
Contributor

Hi @saurav-fermions can you please merge with latest master and resolve the CI failures?

@dsengupta0628

Copy link
Copy Markdown
Contributor

Please fix the CI failure - I think the BUILD entry is wrong. I have no other comments blocking the merge otherwise

…OAD-Project#10414)

DbInstancePinIterator filtered power/ground BTerms out of the top-level
branch.  The top block's ports are the design's primary I/O (including
supply pins) and must stay visible to consumers that walk the top
instance's pins: write_verilog relies on this iterator to emit the
"assign <port> = <net>;" aliases that connect a power/ground port to an
internal supply net whose name differs from the port name.  Filtering
them dropped those connections and broke LVS.

Only the top-level BTerm branch is unfiltered; leaf instance ITerms and
the net-terminal iterators keep the existing supply filtering, so the
memory blow-up addressed by The-OpenROAD-Project#8957 (supply nets on leaf instances whose
LEF does not mark pins as POWER/GROUND) is unaffected.

Adds the write_verilog10 regression covering a PG port aliased to a
differently-named internal supply net.
@saurav-fermions

Copy link
Copy Markdown
Contributor Author

@dsengupta0628 rebased onto current master and pushed (also squashed into one commit).

On the BUILD entry: I sorted the write_verilog10 entry into lexicographic position in ALL_TESTS too (it was appended at the end; the filegroup dict was already fixed earlier). Worth noting though — the BUILD lint jobs were actually green on the previous run (Buildifier format ✅, Buildifier lint ✅). The only failing check was Clang-Tidy-Bazel.

On that Clang-Tidy failure: I ran clang-tidy locally against the project's .clang-tidy on the file this PR touches (src/dbSta/src/dbNetwork.cc). It reports exactly two findings:

dbNetwork.cc:81: warning: included header Search.hh is not used directly [misc-include-cleaner]
dbNetwork.cc:83: warning: included header StringUtil.hh is not used directly [misc-include-cleaner]

Both are at the include block (lines 81/83), nowhere near my change (~line 522), and they reproduce identically on unmodified master — so they aren't introduced by this PR. I'd rather not strip unrelated includes from a shared file in this PR; happy to do it as a separate cleanup if you want that job green here. The rebase should re-run CI against current master, which may clear it anyway.

Verification: rebuilt on current master — write_verilog* and the full dbSta suite pass (76/76). (One tcl.search.annotated_write_verilog failure in my local run is an artifact of only building the openroad target — that OpenSTA test needs the standalone sta binary and fails identically on unmodified master with exit 127.)

Your earlier asymmetry point still stands as noted — the offer to add a pin↔net-term cross-check test, or to make the exposure symmetric for the top block only, is still open if you'd prefer either before merge.

@dsengupta0628

dsengupta0628 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

@dsengupta0628 rebased onto current master and pushed (also squashed into one commit).

On the BUILD entry: I sorted the write_verilog10 entry into lexicographic position in ALL_TESTS too (it was appended at the end; the filegroup dict was already fixed earlier). Worth noting though — the BUILD lint jobs were actually green on the previous run (Buildifier format ✅, Buildifier lint ✅). The only failing check was Clang-Tidy-Bazel.

On that Clang-Tidy failure: I ran clang-tidy locally against the project's .clang-tidy on the file this PR touches (src/dbSta/src/dbNetwork.cc). It reports exactly two findings:

dbNetwork.cc:81: warning: included header Search.hh is not used directly [misc-include-cleaner]
dbNetwork.cc:83: warning: included header StringUtil.hh is not used directly [misc-include-cleaner]

Both are at the include block (lines 81/83), nowhere near my change (~line 522), and they reproduce identically on unmodified master — so they aren't introduced by this PR. I'd rather not strip unrelated includes from a shared file in this PR; happy to do it as a separate cleanup if you want that job green here. The rebase should re-run CI against current master, which may clear it anyway.

Verification: rebuilt on current master — write_verilog* and the full dbSta suite pass (76/76). (One tcl.search.annotated_write_verilog failure in my local run is an artifact of only building the openroad target — that OpenSTA test needs the standalone sta binary and fails identically on unmodified master with exit 127.)

Your earlier asymmetry point still stands as noted — the offer to add a pin↔net-term cross-check test, or to make the exposure symmetric for the top block only, is still open if you'd prefer either before merge.

Thank you. Can you please add a test that cross-checks top-port pins vs net-terms?
Also the clang-tidy-bazel failure is:
ERROR: /home/runner/work/OpenROAD/OpenROAD/src/dbSta/test/BUILD:130:14: Label '//src/dbSta/test:write_verilog10.def' is duplicated in the 'srcs' attribute of rule 'write_verilog10_resources'

To fix this, in src/dbSta/test/BUILD, please delete these 3 lines:
"write_verilog10": [
"write_verilog10.def",
],
glob([test_name + ".*"]) already pulls in write_verilog10.def/.tcl/.ok. The dict is only for inputs whose names don't start with the test name.

I don't follow why the CI is failing consistently- it maybe because Bazel build is not working. Can you please try the above and recheck?

@dsengupta0628 dsengupta0628 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more request. As @gadfort rightly pointed out, we need a test to ensure the timing graph doesn't pick up the bumps like it did before.

src/sta/graph/Graph.cc: makeVerticesAndEdges() calls makePinVertices(network_->topInstance()), which walks network_->pinIterator(inst) → DbInstancePinIterator with top_=true. That is exactly the branch this PR changes. So the PR puts top-level power/ground BTerms back into the timing graph as vertices — bidirect, so two each, driver and load.

Origin of the filter is #8957. Cause there: COVER BUMP cells whose LEF marks the pins INOUT instead of POWER/GROUND, so STA built the graph on the supply nets and memory ballooned.

Note #8957 touched two spots in DbInstancePinIterator::hasNext() — one for instance terminals, one for the top block's terminals. As outlined in my first comment, this PR only changes the second, so the bump cells themselves are still filtered. It is the top-level ports that come back.

I have not measured this, it is from reading the code, so worth confirming: on a design with a large number of power and ground ports, compare the graph vertex count before and after.

If the count does grow, one option is to read the port connections for write_verilog off the block terminals directly, leaving the graph path untouched.

Either way, please add a test - #8957 went in without one. src/dbSta/test is the right place, next to write_verilog10. Something like: a small LEF with a bump-like cell whose pins are INOUT, a DEF tying it and several top-level power/ground ports to one supply net, then print the graph vertices with sta::vertex_iterator and dump the verilog with make_result_file + report_file. The .ok then covers both sides at once — the supply pins stay out of the vertex list, and the assign lines stay in the verilog. Register it in CMakeLists.txt and in ALL_TESTS in BUILD.

If the vertex order out of that iterator is not stable, sort before printing.

Addresses review feedback on The-OpenROAD-Project#10414:

- New supply_port_graph test guards both sides at once, as requested: the
  timing-graph vertex list must not contain the top-level power/ground
  terminals (the growth The-OpenROAD-Project#8957 fixed), while the top instance pin walk must
  still expose them and write_verilog -include_pwr_gnd must still emit the
  assign aliases.  It also cross-checks the supply BTerms odb reports on each
  supply net against the pin walk, so the two views cannot silently diverge.
  Vertex and pin names are sorted before printing for a stable golden.
  Verified discriminating: reverting the dbNetwork.cc change makes the test
  fail (supply pins drop out of the pin walk and the assign lines disappear).

- Remove the write_verilog10 entry from the per-test resources dict in
  src/dbSta/test/BUILD.  glob([test_name + ".*"]) already picks up
  write_verilog10.def, so the explicit entry duplicated the label and broke
  the Bazel build (Clang-Tidy-Bazel).
@github-actions github-actions Bot added size/M and removed size/S labels Aug 30, 2026
@maliberty

Copy link
Copy Markdown
Member

I think we should avoid iterator asymmetry.

@gadfort

gadfort commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

It would require some changes in opensta, but it seems like we need a way for the verilog writer and the timing graph to use different iterators.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenROAD doesn't write internal power connections ( multiple pins connected to same power rail ).

4 participants