Skip to content

grt: enhance FastRoute NDR handling - #11963

Merged
osamahammad21 merged 24 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:grt-update-fr-ndr-handling
Nov 5, 2026
Merged

osamahammad21 merged 24 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:grt-update-fr-ndr-handling

Conversation

@jfgava

@jfgava jfgava commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Problem

During the 2D stages, FastRoute checks that each NDR net fits in a single layer of every edge it uses. When no layer could host the net, Graph2D::getCostNDRAware added 100 × the net's edge cost to the shared edge usage. Every later NDR net on that edge was charged the same, even when it fit.

For example, an edge with three layers of 2 tracks each cannot host an NDR net of cost 3. That edge looked about 300 tracks over capacity, although it still had room for three regular nets. As a result:

  • Regular nets were pushed off edges they fit in.
  • The overflow iterations chased overflow that did not exist.
  • The inflated usage could exceed the 2D usage limit, triggering the GRT-0228.

Implementation

  • True usage. The shared usage always gets the net's real edge cost. The tracks an NDR net misses on its best layer are recorded as its NDR deficit on the edge (NDRUsage::deficit, Edge::ndr_deficit, plus a running total).
  • Pricing for NDR nets only. FastRouteCore::getUsageNDRAware makes an edge with a deficit look overflowed by kNdrDeficitCost (100) tracks per missing track, but only to NDR nets. Regular nets see the true usage. It feeds the maze cost and the L, Z, spiral and monotonic pattern routes. The NDR nets on an edge share its deficit (getNDRDeficitIfRouted), so a net that fits also sees the nets it leaves without room.
  • Rip-up. NDR nets are rerouted off edges with a deficit, even when the edge is below capacity.
  • Overflow. The 2D overflow includes the total deficit, in both the incremental count and its full-scan reference. The iteration loop, best-solution tracking and soft-NDR demotion therefore still react to it. The NDR fallback after layer assignment also triggers whenever a deficit is left.
  • Net order. StNetOrder adds 100 × an NDR net's own deficit to the net's congestion key. The key is now capped at the int16_t maximum instead of wrapping.
  • Stale records. initNDRnets clears the per-edge NDR records of the previous run. Without this, a new net allocated at the address of a deleted one was taken for a net already using the edge.
  • Cleanup. The multiplier, hasNDRCapacity, and the unused net name copy in getCostNDRAware are removed.

Tests

  • New: NDR deficits. Two tests in the NDRDeficitTest fixture of TestOverflow:
    • the 3 layers × 2 tracks example with an NDR net of cost 3: usage 3, deficit 1, three regular nets still fit, 2D overflow 1;
    • two NDR nets sharing one edge's deficit.
  • New: re-init. A TestGraph2D test checks that a same-size re-init drops the previous run's NDR records. It fails without the fix.
  • Updated. AccountsForNDRDeficitsAndCancellation (previously AccountsForNDRPenaltiesAndCancellation), and few goldens.

Type of Change

  • New feature

Impact

Better handling of routing resources when dealing with NDR nets during FastRoute 2D phases.

Verification

  • I have verified that the local build succeeds (./etc/Build.sh).
  • I have run the relevant tests and they pass.
  • My code follows the repository's formatting guidelines.
  • I have included tests to prevent regressions.
  • I have signed my commits (DCO).

When no layer of an edge could host an NDR net, getCostNDRAware added
100 times the net's edge cost to the shared 2D usage, and every later
NDR net on that edge was charged the same, even when it fit. All nets
then saw the edge as overflowed although it still had room for regular
nets, the overflow iterations chased overflow that did not exist, and
the inflated usage could exceed the usage limit (GRT-0228 on
nangate45/mempool_group).

The shared usage now gets the true edge cost. The tracks an NDR net
misses on its best layer are recorded as its NDR deficit on the edge,
and only the NDR nets see it:
- NDR nets price an edge with a deficit, in the maze and pattern
  routing costs, as overflowed by kNdrDeficitCost (100) tracks per
  missing track. The NDR nets on an edge share its deficit, so the one
  that fits can also move away.
- NDR nets are ripped up from edges with a deficit.
- The 2D overflow counts the deficits, and the NDR fallback after layer
  assignment also triggers when one is left.
- StNetOrder counts the deficit of an NDR net in its overflow, and
  saturates the int16 key instead of wrapping.

initNDRnets now clears the NDR records of the previous run: resize keeps
them on a same-sized grid, and a new net allocated at the address of a
deleted one was taken for a net already using the edge.

The unused net name copy is removed from getCostNDRAware.

Golden updates:
- ndr_1w_3s: wirelength 1684 -> 1663 um, vias 206 -> 211
- soft_ndr_4w_6s: wirelength 1850 -> 1756 um, vias 198 -> 195
- soft_ndr_escalation: wirelength 1814 -> 1872 um, vias 202 -> 199. The
  NDR nets are demoted at the iteration limit instead of on stagnation,
  since the overflow keeps improving.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
Replacing the NDR overflow multiplier with NDR deficits changes the
global routes of jpeg_sky130hd and jpeg_sky130hs, and the antenna repair
after detailed routing leaves one more violation in each: 0 -> 1 and
1 -> 2. The violations are on regular signal nets (met1 side area
ratio), not on NDR nets. Timing otherwise holds (DRT WNS -0.481 ->
-0.423 ns and -0.371 -> -0.363 ns), and every other limit is still met,
so only the DRT::ANT::errors limits are raised.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
Limits from the flow_metrics.tcl formulas on this branch's results: clock skew 0.392 -> limit 0.470, antenna errors 1.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
@jfgava jfgava self-assigned this Oct 23, 2026

@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 introduces the concept of NDR deficits to track and price Non-Default Routing (NDR) nets that cannot fit on any single layer of an edge, separating deficits from edge usage and integrating them into routing costs, rip-up checks, and net ordering. Feedback on these changes highlights two key improvements: first, in Graph2D::initNDRnets(), the multi-arrays should be resized before calling clearNDRnets() to prevent potential out-of-bounds accesses when grid dimensions change; second, in getUsageNDRAware(), using edge-specific capacities via getEdgeCapacity() instead of nominal global capacities would more accurately represent congestion on edges with reduced capacity.

Comment thread src/grt/src/fastroute/src/graph2d.cpp Resolved
Comment thread src/grt/src/fastroute/src/FastRoute.cpp Resolved
Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
@github-actions github-actions Bot added size/XL and removed size/L labels Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@jfgava jfgava changed the title grt: update FastRoute NDR handling grt: enhance FastRoute NDR handling Oct 27, 2026
Regenerate the soft_ndr_4w_6s and soft_ndr_escalation goldens for the per-edge capacity in getUsageNDRAware, and add a unit test that pins the price of a reduced edge.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
@jfgava
jfgava marked this pull request as ready for review October 27, 2026 20:46
@jfgava
jfgava requested review from a team as code owners October 27, 2026 20:46
@jfgava
jfgava requested a review from eder-matheus October 27, 2026 20:46
When a net leaves an edge, re-reserve the layers of the NDR nets that
miss tracks there, in net id order, so their deficit does not outlive
the net that caused it.

Gate the 3D maze routing on the 2D usage overflow only: the NDR deficit
comes from first-fit 2D layer reservations, which layer assignment can
improve on.

Sum the edge deficits in the full-scan overflow references, so that the
overflow checks catch a drifting running total.

ndr_1w_3s now converges after one extra iteration instead of three,
with the same routes.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
…ROAD into grt-update-fr-ndr-handling

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
Regenerate the metrics and limits of ibex_sky130hd, ibex_sky130hs and
jpeg_sky130hd from the Bazel run after merging master. This branch's
global routing demotes fewer NDR clock nets, which changes post-route
slew, capacitance and antenna results on these designs.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
@jfgava
jfgava requested a review from luis201420 October 28, 2026 16:00
@luis201420

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@jfgava

jfgava commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@jfgava

jfgava commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

The last commits addressed these comments from Eder:
PR #11963: grt: enhance FastRoute NDR handling
Modules: grt (FastRoute), test/ (Bazel flow metrics)

== Priority 1 (correctness) ==

src/grt/src/fastroute/src/graph2d.cpp:1171 bug (minor): an NDR deficit can gostale. A net's deficit is set once, in reserveNDRCapLayer, and only removedwith that net. When another net's layer is released, the remaining nets arenot re-checked. Example with tracks {2,2,3} and two NDR nets of width 3:A takes L2, B gets deficit 1. Rip up A: L2 has 3 free tracks again, butedge.ndr_deficit and the total stay at 1, so the 2D overflow counts 1.getNDRDeficitIfRouted(A) also returns 1, so A is priced off an edge it fitson. It heals when B is ripped on the next maze pass, or when copyBR rebuildsall usage. The old charged_overflow flag had the same staleness, but the 2Doverflow total now depends on the deficit. Suggest re-checking the remainingdeficit nets on the edge at release (the map is tiny). Test:graph.updateUsageH(1, 0, ndr_net_, -kNdrWidth); // the net that fits leavesEXPECT_EQ(graph.getTotalNDRDeficit(), 0);
src/grt/src/fastroute/src/FastRoute.cpp:2759,2769 bug: "An NDR deficit leftin 2D always becomes 3D overflow" isn't true. reserveNDRCapLayer packs netsfirst-fit, so a deficit can exist even when some layer assignment fits.Example: L0 = 3 tracks, L1 = 2 tracks. A (width 2) is added first and takesL0, so B (width 3) gets deficit 1, but A on L1 and B on L0 would fit. Iflayer assignment finds that, no net is demoted: disableNDRForCongestedNets(unchanged by this PR) only checks 2D usage overflow and 3D overflow.past_cong (getOverflow2Dmaze) still counts the deficit, so thepast_cong == 0 check fails and mazeRouteMSMDOrder3D is skipped for thewhole design. The old code had inflated usage on that edge, so the netswere demoted and the 3D maze still ran. Suggest leaving the deficit out ofthe 3D-maze check (or recomputing it from the 3D assignment), and fixingthe comment.
src/grt/src/fastroute/src/maze.cpp:2310,2392 suggestion: the full-scanreference adds the same running ndr_deficit_total_ as the incremental path,so the overflowcheck (GRT-904/905) can't catch the total drifting from thesum of Edge::ndr_deficit. Summing edge.ndr_deficit in the scan loops wouldmake it a real check.

== Priority 2 (QoR) ==

src/grt/test/soft_ndr_escalation.ok question: wirelength goes 1814 -> 2052 um(+13%), and NDR demotion now happens at the iteration limit (15) instead ofon stagnation (12). The PR body doesn't mention it, and the commit messagestill says 1872. Expected?
test/aes_sky130hd.metrics_limits, test/jpeg_sky130hd.metrics_limits question:DRT::ant::errors is raised 0 -> 1 on both. A commit message explainsjpeg_sky130hd, but nothing explains aes_sky130hd, and the PR body mentionsneither. The base .metrics files are stale (gpl metrics change even thoughthe flow's gpl uses RUDY, not FastRoute), so the metrics diff doesn't showthis PR's own effect. Could you compare before/after on the same master,through DRT? The 21-checkpoint replay only covers the first global_route.

== Priority 3 (testing) ==

Missing tests: the stale-deficit case above, and newRipupCheck /newRipupCongestedL ripping up an NDR net on a deficit edge that is undercapacity. No test calls either function.

== Priority 6 (process) ==

Some commit messages don't match the final diff: jpeg_sky130hs and theaes_sky130hs antenna limit are mentioned but neither changed, and the goldenwirelength numbers are out of date. Worth fixing, since merge commits keep them.

== Overall ==
Needs changes. Keeping the NDR penalty out of the shared usage is the right
fix, and the bookkeeping is easy to follow. Main ask: stop the deficit from
blocking the 3D maze when layer assignment resolved it, and explain the
soft_ndr_escalation wirelength and the raised antenna limits.

@luis201420 luis201420 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.

Just to clarify, my comments are only suggestions and nothing blocking. The PR looks good to me.

Comment thread src/grt/src/fastroute/src/graph2d.cpp Resolved
Comment thread src/grt/src/fastroute/src/route.cpp Resolved
Comment thread src/grt/src/fastroute/src/maze.cpp Resolved
Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
@jfgava

jfgava commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

@osamahammad21 QoR metrics degraded for some flow tests due to more detours caused by fewer soft-NDR demotion. The next PR should fix this by restoring the routing state. No issues for public and private CI

Regenerate the metrics and limits of ibex_sky130hd from the Bazel run
after merging master. Results change from placement onward, which
moves the post-route slew and capacitance slacks past their limits.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
…ROAD into grt-update-fr-ndr-handling

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
Regenerate the metrics and limits of aes_nangate45, gcd_nangate45,
jpeg_sky130hd and jpeg_sky130hs from the Bazel run after merging
master. Post-route slew, capacitance, clock skew and antenna results
moved past their limits on these designs.

Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
@jfgava
jfgava requested a review from osamahammad21 November 4, 2026 23:45
@osamahammad21
osamahammad21 merged commit a6e7f50 into The-OpenROAD-Project:master Nov 5, 2026
20 checks passed
@openroad-ci
openroad-ci deleted the grt-update-fr-ndr-handling branch November 5, 2026 13:30
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.

3 participants