Skip to content

drt: limit detailed-route grid graph to the routing-layer range#10654

Open
mguthaus wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
VLSIDA:drt-gridgraph-routing-layer-opt
Open

drt: limit detailed-route grid graph to the routing-layer range#10654
mguthaus wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
VLSIDA:drt-gridgraph-routing-layer-opt

Conversation

@mguthaus

Copy link
Copy Markdown
Contributor

When a design's top routing layer is below the technology's top metal, the detailed-route grid graph is still built across the full layer stack — wasting memory and runtime on layers that can't be routed.

FlexGridGraph::initTracks() adds every routing layer in the tech to the grid, and initGrids() sizes nodes_ plus the per-node arrays (prevDirs_, srcs_, dsts_, guides_) and the maze-search bounds from that full set. But routing edges (initEdges()) and access vias are already capped at TOP_ROUTING_LAYER, so the nodes above it carry no edges — they're pure overhead.

This skips routing layers above TOP_ROUTING_LAYER when building the grid, so the graph spans only the routing range. TOP_ROUTING_LAYER defaults to INT_MAX, so this is a no-op unless the top routing layer is explicitly lowered (set_routing_layers / a platform or design cap).

Only the top side is trimmed; layers at/below BOTTOM_ROUTING_LAYER are left untouched so pin access is unaffected.

Motivation / results

Measured on the gt2n platform (a 2 nm nanosheet platform with backside power, exposing metal M0–M13, added to ORFS in The-OpenROAD-Project/OpenROAD-flow-scripts#4277). gt2n designs route well below the M13 top (gcd ~M5, jpeg ~M9, aes ~M10), so the upper layers are pure overhead:

  • gcd with the top routing layer at the tech top (M13) → routed DB is bit-identical to before (true no-op).
  • gcd with the top routing layer lowered to M5 (8 of 12 routing layers unused) → detailed-route wall time −10%, peak memory −14%, 0 DRC, equivalent wirelength.

The companion ORFS change (The-OpenROAD-Project/OpenROAD-flow-scripts#4277) sets MAX_ROUTING_LAYER per gt2n design to the layers actually used, which is what makes this trim pay off.

Behavior note

When the top routing layer is below the tech top, the smaller grid changes maze-search node indexing, so the result isn't bit-identical to the un-trimmed run — it's an equal-quality, DRC-clean solution, not the same one. At the default top routing layer it's bit-identical, so designs that route the full stack are unaffected.

Testing

Routed gt2n/gcd before/after on the same block — verified 0 DRC and equivalent QoR at the lowered top layer (M5), and a bit-identical routed DB at the tech top (M13).

@mguthaus mguthaus requested a review from a team as a code owner June 14, 2026 14:27
@mguthaus mguthaus requested a review from osamahammad21 June 14, 2026 14:27

@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 FlexGridGraph::initTracks in src/drt/src/dr/FlexGridGraph.cpp to skip initializing tracks for layers above TOP_ROUTING_LAYER. This optimization prevents unnecessary grid sizing, reducing memory usage and runtime when the top routing layer is explicitly lowered below the technology top. There are no review comments, so I have no feedback to provide.

@maliberty

Copy link
Copy Markdown
Member

If there are bterm or bump above the top routing layer we may still need to add vias. I'm not sure if the graph is required or not

@mguthaus

Copy link
Copy Markdown
Contributor Author

@maliberty It will default to all layers, so this would be used for blocks that don't access the top most layers. It would make since not to set the max layer if you need to access those. Are there any test cases of this?

When we get to 20+ layers (4-5 backside + 15+ front side) this will get more significant of a run time. 10% on gcd is quite significant and it gets more significant with larger designs.

@maliberty

Copy link
Copy Markdown
Member

There has been proprietary designs that have bumps and require this handling. @osamahammad21 is the graph needed for these layers to make this work? If so, you could do some up front analysis to decide whether the graph can be pruned or not.

@mguthaus

mguthaus commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@maliberty I guess my question is, what is the goal functionality of TOP_ROUTING_LAYER? When I hear that variable, I think "don't put any wires above that layer" and if there were bumps or pins it should be an error because you can't access them without adding at least a contact enclosure above that layer.

@mguthaus

Copy link
Copy Markdown
Contributor Author

Do those designs set TOP_ROUTING_LAYER? If they don't it doesn't matter.

@maliberty

Copy link
Copy Markdown
Member

It is essentially the highest layer to add wires to but you can still via up to a bump. Similar to the lowest routing layer still allows vias down to pins.

@mguthaus

Copy link
Copy Markdown
Contributor Author

I'm still unclear. Let's consider the other side. If you have cell pins on M0 and set the routing BOTTOM_ROUTING_LAYER to M2, would that fail? Should it fail? This requires an M1 enclosure added which is not a routing layer.

@osamahammad21

Copy link
Copy Markdown
Member

There has been proprietary designs that have bumps and require this handling. @osamahammad21 is the graph needed for these layers to make this work? If so, you could do some up front analysis to decide whether the graph can be pruned or not.

No, the graph isn't needed for those layers. We preprocess these bterms and insert a via stack from the pin shape down to the TOP_ROUTING_LAYER. The maze search then simply routes to that pre-built via stack, so in practice the nodes above TOP_ROUTING_LAYER are never used as routing targets.

I'm still unclear. Let's consider the other side. If you have cell pins on M0 and set the routing BOTTOM_ROUTING_LAYER to M2, would that fail? Should it fail? This requires an M1 enclosure added which is not a routing layer.

It wouldn't fail, and it shouldn't. This is in fact the common case as most designs have pins on M1 while BOTTOM_ROUTING_LAYER is M2. DRT is forbidden from placing routing segments below BOTTOM_ROUTING_LAYER (or above TOP_ROUTING_LAYER), but it is still free to place vias outside that range, including the M1 enclosure needed to reach the pin. The key point is that the bottom/top routing layer bounds constrain metal segments, not vias.

@mguthaus

Copy link
Copy Markdown
Contributor Author

@osamahammad21 Got it. So this changed I made should work fine with that methodology.

@osamahammad21

Copy link
Copy Markdown
Member

@osamahammad21 Got it. So this changed I made should work fine with that methodology.

True, but I am running a CI to make sure that I didn't miss corner case where we use nodes above the top routing layer. Once I confirm, I'll approve and merge.

@osamahammad21

Copy link
Copy Markdown
Member

After running the CI I found that initMazeCost writes fixed-shape costs across the full stack, so a fixed shape above TOP_ROUTING_LAYER now hits a node that no longer exists and crashes (seen on ihp-sg13g2). So the trim needs a bit more care on the costing side before this is safe to merge.

FlexGridGraph::initTracks() added every routing layer in the tech to the grid,
sizing nodes_, the per-node arrays (prevDirs_/srcs_/dsts_/guides_), and the
maze search bounds across the full layer stack. Routing edges and access vias
are already capped at TOP_ROUTING_LAYER, so layers above it were dead weight.
Skip routing layers above TOP_ROUTING_LAYER so the grid graph spans only the
routing range. Default TOP_ROUTING_LAYER is INT_MAX, so this is a no-op unless
the top routing layer is explicitly lowered.

Once the grid is trimmed it no longer spans the full layer stack, so maze-cost
init must not assume every tech layer maps to a grid node. initMazeCost_fixedObj
and initMazeCost_terms looped over the whole stack and called
getMazeZIdx(layerNum) for routing layers above TOP_ROUTING_LAYER, returning an
out-of-range z that the cost path dereferenced (getLayerNum -> zCoords_[z]),
crashing on platforms with fixed shapes or instance pins above the top routing
layer (e.g. ihp-sg13g2, with PDN and sg13g2_io pins on TopMetal above Metal5).
Guard both so fixed-shape costing skips layers outside the grid's
[getMinLayerNum, getMaxLayerNum] span. The skip is before any cost call, and is
a no-op when the grid spans every routing layer. (The setBlocked/setGuide paths
in initMazeCost_planarTerm, modBlockedEdgesForMacroPin and the guide helper are
already bounds-checked, so they need no change.)

Verified:
- gt2n gcd: at the tech-top layer the routed DB is bit-identical to before
  (true no-op); with the top routing layer lowered to M5, detailed-route wall
  time dropped ~10% and peak memory ~14%, 0 DRC.
- ihp-sg13g2 gcd (fixedObj) and i2c-gpio-expander (terms) crashed before the
  guard and route DRC-clean after it.

Signed-off-by: mrg <mrg@ucsc.edu>
@mguthaus mguthaus force-pushed the drt-gridgraph-routing-layer-opt branch from e213c03 to 0fe62b1 Compare June 16, 2026 16:49
@mguthaus

mguthaus commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

@osamahammad21 Thanks for pointing me to those tests. I was able to replicate the problem and also searched for a few other cases using getMazeZIdx(layerNum) and made a fix. Though, I did not modify the tests to lower the TOP_ROUTING_LAYER in the committed tests, instead I just replicated locally. Let me know if you think I should do that, but it might change the QoR results for the tests.

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