Skip to content

grt,cts,est: backside-aware fixes (cross-side direction check, NDR creation, parasitic midpoint)#10600

Open
mguthaus wants to merge 3 commits into
The-OpenROAD-Project:masterfrom
mguthaus:grt-cross-side-direction-check
Open

grt,cts,est: backside-aware fixes (cross-side direction check, NDR creation, parasitic midpoint)#10600
mguthaus wants to merge 3 commits into
The-OpenROAD-Project:masterfrom
mguthaus:grt-cross-side-direction-check

Conversation

@mguthaus

@mguthaus mguthaus commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Three small backside-aware fixes uncovered while bringing up the
gt2n BSPDN PDK in OpenROAD-flow-scripts. Each is independent and
sits as its own commit. The underlying theme is the same: routines
that walk dbTech::findRoutingLayer(1..count) without an
isBackside() guard misbehave on a tech whose routing-layer
enumeration interleaves a backside stack (BPR, BM*, BRDL) with the
familiar frontside stack (M0 .. RDL).

Commits

  1. grt: skip cross-side pairs in checkAdjacentLayersDirection
    GRT-126 is a hard error fired when two consecutive routing levels
    share a preferred direction. On a BSPDN tech the level-l /
    level-l+1 pair can straddle the backside boundary (e.g. BPR(H) and
    M0(H)). Those layers are not physical neighbors and direction
    agreement across the boundary is not a misconfiguration. Skip the
    pair when isBackside() differs.

  2. cts: skip backside layers in writeClockNDRsToDb
    The default-NDR creation loop builds a dbTechLayerRule for every
    routing layer in the tech. Clock trees route on the frontside.
    The backside rules are derived from backside design rules and
    would never apply to a clock net, but still live in the
    dbTechNonDefaultRule and could leak through by-name lookups.

  3. est: keep cut-resistance fallback midpoint on the frontside stack
    computeAverageCutResistance falls back to
    getRoutingLayerCount() / 2 when block max routing layer is unset.
    With backside layers in the count, that midpoint lands on the
    backside via stack instead of the signal-routing via stack the
    function is meant to characterize. Anchor the fallback at
    firstFrontsideRoutingLayer() and halve the frontside-only count.
    Legacy non-backside techs are unchanged.

Why now / impact

The GRT-126 case is not theoretical. Lowering MIN_ROUTING_LAYER to
M0, a perfectly reasonable choice that @gadfort appears to have been
running when he flagged this, is enough to make the check walk the
BPR(H) / M0(H) pair and abort the flow with a hard error on a valid
BSPDN PDK. The default ORFS gt2n config sets MIN_ROUTING_LAYER=M2
today and so happens to skip over the boundary, which masks the bug;
any config that opens the bottom of the stack hits it immediately.

The CTS and EST cases are quieter. The bogus NDR rules on backside
layers never get applied to a clock net in practice, and the EST
fallback only fires when block max routing layer is unset. They are
the same underlying pattern and worth cleaning up at the same time.

Test plan

  • Local incremental rebuild clean.
  • gt2n/gcd ORFS run through 5_1_grt clean with the series
    applied (no GRT-126, no behavioral change vs. unpatched for
    that config since MIN_ROUTING_LAYER=M2 and block max is set).
  • Existing GRT / CTS / EST regressions cover the no-backside path,
    which is what the legacy-equivalence arms of each patch preserve.

Related

@gadfort flagged the GRT-126 case on a review comment elsewhere.
Filing the cluster of three together since they all share the same
underlying pattern.

@mguthaus mguthaus requested review from a team as code owners June 6, 2026 16:18
@github-actions github-actions Bot added the size/S label Jun 6, 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 changes to handle backside routing layers appropriately across TritonCTS, EstimateParasitics, and GlobalRouter. Specifically, it skips backside routing layers when writing clock NDRs, refines the fallback logic for estimating parasitics to focus on the frontside routing stack, and avoids adjacent layer direction checks across the backside/frontside boundary. The review feedback highlights potential segmentation faults in TritonCTS.cpp and GlobalRouter.cpp due to missing null checks on routing layer pointers returned by findRoutingLayer before calling isBackside().

Comment thread src/cts/src/TritonCTS.cpp
Comment thread src/grt/src/GlobalRouter.cpp
@gadfort

gadfort commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

@mguthaus I just reran with this PR and no errors this time. Thanks

mguthaus added 3 commits June 7, 2026 15:18
checkAdjacentLayersDirection walks tech->findRoutingLayer(l) and
findRoutingLayer(l+1) and errors GRT-126 when the two share a preferred
direction. dbTech::findRoutingLayer indexes both frontside and backside
layers by routing level, so the level-l / level-l+1 pair can straddle
the backside / frontside boundary (e.g. BPR(H) at level k and M0(H) at
level k+1 in a BSPDN tech). Those layers are not physical neighbors;
they sit on opposite sides of the substrate, and direction agreement
across the boundary is not a misconfiguration.

Skip the pair when the two layers disagree on isBackside(). Does not
trip in flows that set MIN_ROUTING_LAYER above the boundary (as the
gt2n ORFS platform does today with M2), but the check would fire as a
hard error if MIN_ROUTING_LAYER were lowered to M0 or below.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
writeClockNDRsToDb walks tech->findRoutingLayer(1..count) and creates a
dbTechLayerRule under the clock NDR for every routing layer in the
tech, including backside layers (BPR, BM*, BRDL on a BSPDN tech).
Clock trees are routed on the frontside; the backside NDR rules pick
up backside-specific widths and pitches that would never be applied to
a clock net but still live in the dbTechNonDefaultRule and could leak
through downstream lookups by layer name.

Guard the loop with isBackside() so the NDR only covers layers that
clock routing can actually use.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
computeAverageCutResistance falls back to getRoutingLayerCount() / 2
when the block has no explicit max routing layer set. On a BSPDN tech
the count includes backside routing layers (BPR, BM*, BRDL) sitting at
low routing levels, so the midpoint lands on the backside stack and
the loop that averages cut-layer resistance walks an inactive part of
the via stack instead of the signal-routing layers it is meant to
characterize.

Use firstFrontsideRoutingLayer() to anchor the fallback at the first
frontside level and halve the frontside-only count from there. Legacy
techs without backside layers (first frontside == level 1) keep
exactly the previous count / 2 behavior.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
@mguthaus mguthaus force-pushed the grt-cross-side-direction-check branch from 3dd35b3 to 778e7e9 Compare June 7, 2026 22:19
@mguthaus

mguthaus commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

Had to rebase/push again since Jenkins randomly failed.

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.

2 participants