Skip to content

Add LEF58_BACKSIDE support for backside-power-delivery PDKs#10547

Merged
maliberty merged 24 commits into
The-OpenROAD-Project:masterfrom
VLSIDA:bspdn
Jun 4, 2026
Merged

Add LEF58_BACKSIDE support for backside-power-delivery PDKs#10547
maliberty merged 24 commits into
The-OpenROAD-Project:masterfrom
VLSIDA:bspdn

Conversation

@mguthaus

@mguthaus mguthaus commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds first-class support for LEF58_BACKSIDE-tagged layers and the LEF58_BACKSIDE_BRIDGE macro property across ODB, DRT, PDN, and PSM so OpenROAD can ingest tech LEFs from backside-power-delivery (BSPDN) PDKs without crashing the front-side router and without producing spurious power-grid connectivity errors.

Eight commits, each scoped to one module:

  1. odb: add dbTechLayer::isBackside() and a parser for the LEF58_BACKSIDE property (previously logged as unsupported and discarded).
  2. drt: filter backside layers out of TritonRoute's tech model at every ingest point (setLayers, setTracks, setBTerms, setTechViaRules, setNDRs, updateNetRouting, updatefrAccessPoint). Without this DRT crashes in FlexTAWorker::initFixedObjs when it tries to build a default via on a backside cut layer that has no geometry.
  3. pdn: warn when add_pdn_connect is given two layers that disagree on isBackside(). A standard cut-layer via cannot bridge front-side to backside; the connection has to come from a tap cell.
  4. psm: skip backside layers when picking the layer for ITerm base nodes. Without this every cell ITerm on a BSPDN PDK reports PSM-0039 'Unconnected instance' because the virtual base node lands on a backside layer that has no shapes.
  5. psm: multi-seed the connectivity BFS from every top-layer node. The PG network on a BSPDN PDK legitimately has more than one component touching the top layer (each bridge cell forms its own subgraph as seen from above); without multi-seeding the BFS misses subgraphs and reports PSM-0038 spuriously.
  6. psm: regression test check_power_grid_backside.tcl exercising both PSM fixes on a tiny synthetic backside design (LEF + DEF under src/psm/test/backside_data/). Also tightens the BFS to skip isolated seed nodes via find() instead of throwing on at().
  7. pdn: regression test add_pdn_connect_backside_warn.tcl reusing the same synthetic LEF/DEF to verify the cross-boundary warning fires.
  8. odb: add dbMaster::isBacksideBridge() and a parser for the LEF58_BACKSIDE_BRIDGE macro property. Lets a PDK author flag a tap cell as physically bridging the front-side and backside power stacks, instead of leaving downstream tools to infer the bridge from multi-port-PIN geometry. No in-tree consumers yet; this is a foundational API for follow-on PDN/PSM work.

Test coverage

Unit tests in src/odb/test/, src/psm/test/, and src/pdn/test/ cover the new functionality directly. No existing tests should be affected -- the new code paths are gated on LEF58_BACKSIDE / LEF58_BACKSIDE_BRIDGE, which no shipped OpenROAD test PDK uses today, so on front-side-only PDKs the new code paths reduce to no-ops (the multi-seed BFS collapses to the single-seed behavior when the network has only one connected component touching the top layer).

The full end-to-end PnR flow on a real BSPDN PDK is not tested here, because no LEF58_BACKSIDE-tagged tech ships in OpenROAD's test tree. The full flow is exercised separately via an ORFS PDK update that adds the GT2N 2nm PDK; that ORFS work depends on the OpenROAD changes in this PR landing first.

Out of scope

  • RCX backside-aware coupling extraction (would compute spurious front<->back coupling cap; matters for full PEX signoff, not for the PnR happy path).
  • A first-class PDN/PSM consumer of isBacksideBridge(). The parser and accessor land here; consumers can opt in incrementally.

Test plan

  • ctest -R odb.lef58_backside_bridge passes
  • ctest -R psm.check_power_grid_backside passes
  • ctest -R pdn.add_pdn_connect_backside_warn passes
  • No regressions in ctest -L odb, -L psm, or -L pdn on front-side-only PDKs (multi-seed BFS reduces to single-seed)
  • (Maintainers) Verify CI on full test suite

🤖 Generated with Claude Code

mguthaus added 7 commits May 28, 2026 15:45
LEF 5.8 lets a tech LEF mark routing and cut layers as backside via
"PROPERTY LEF58_BACKSIDE BACKSIDE ;". Backside layers are used by
buried-power-rail (BPR) and backside power-delivery network (BSPDN)
flows on 2nm-class technologies.

Previously, the property was logged as unsupported (ODB-0388) and
discarded. This commit:

* Adds a parser for LEF58_BACKSIDE (modelled on RECTONLY).
* Stores the flag on dbTechLayer via a new flags_.is_backside bit
  (taken from spare_bits).
* Exposes dbTechLayer::setBackside() / isBackside() via the public
  API.
* Wires the parser into the ROUTING and CUT branches of
  lefin::createLayer so the property is consumed rather than warned
  about.

The flag has no in-tree consumers yet; downstream modules (DRT, GRT,
PDN, DPL, RCX) will be updated in follow-up commits to skip backside
layers from front-side routing while still letting the geometry round-
trip through DEF/GDS for downstream LVS/PEX tools.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
OpenROAD's detailed router (TritonRoute) has no notion of front- versus
back-side metal stacks. On a backside-power PDK (GT2N 2nm with BPR /
BM* / BRDL), the router tries to build default vias for the backside
cut layers (BV0..BV4) and crashes when those vias have no front-side
geometry. Even after a defensive null-guard on the via probes, every
downstream consumer (track grids, BTerms, special-net wires, access
points, NDRs, via generate rules) still tries to look up backside
layers in frTech and crashes.

This commit filters backside layers out of DRT at every ingest point:

* setLayers     - skip ROUTING / CUT / MASTERSLICE layers tagged
                  isBackside(); they never appear in frTech.
* setTracks     - skip track grids on backside layers.
* setBTerms     - skip BPin shapes on backside layers (e.g. block-
                  level VDD/VSS pins routed on BPR).
* setTechViaRules - skip generate rules that reference any backside
                  layer.
* setNDRs       - skip per-layer / via / via-rule NDR entries that
                  reference backside layers.
* updateNetRouting (signal path) - skip path segments and vias whose
                  layer doesn't exist in frTech; works because the
                  router's name2layer_ table already excludes backside
                  layers.
* updateNetRouting (special path) - skip SWire boxes and SBox vias
                  on backside layers (BPR followpins, backside
                  stripes generated by PDN).
* updatefrAccessPoint - return false (and skip the access point in
                  callers) when the AP is on a backside layer.

The frLayer wrapper gets a passthrough isBackside() that consults the
underlying dbTechLayer::isBackside() (added by the previous commit).

With this, gt2n/gcd routes end-to-end without the previously needed
null-guard in FlexTAWorker::initFixedObjs; the null-guard is reverted
in the same commit because the filter supersedes it. asap7/gcd is
unaffected (no layers there report isBackside).

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
A standard cut-layer via cannot bridge a front-side metal to a backside
metal (BPR, BM*, BRDL) in a backside-power-delivery PDK. The bridge
has to come from a TSV-like tap cell whose layout already stitches the
two sides together.

Today the user can write

    add_pdn_connect -grid {grid} -layers {M1 BPR}

without any feedback, even though PDN cannot generate a via to satisfy
it. The connection just silently fails to materialize.

This commit adds a warning (PDN-1200) when the two layers of an
add_pdn_connect rule disagree on isBackside(). The warning is
informational only - we don't error, because the user may know that a
tap cell is providing the bridge and is intentionally documenting
intent in the .tcl. The warning at least makes the unusual topology
explicit.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
PSM's ITerm shape-generation puts a 'virtual base node' on the layer
returned by getTech()->findRoutingLayer(1). On a backside-power PDK
(LEF58_BACKSIDE present), ODB orders backside metals at the low end
of the routing-layer index space - on GT2N findRoutingLayer(1) is
BRDL, with BPR at level 6 and the lowest front-side metal M0 starting
at level 7.

The design has no BRDL geometry, so every base node lands on an
orphan layer and the IRSolver flags every cell as 'Unconnected
instance' (PSM-0039), making analyze_power_grid unusable.

Scan upward through the routing-layer index space and use the first
front-side layer instead. On front-side-only PDKs this still resolves
to the original layer (findRoutingLayer(1)), so existing flows are
unchanged.

This is one piece of full BSPDN IR-drop support; the remaining piece
is that PSM does not currently model the M1<->BPR bridge inside a tap
cell, so PG-net IR drop on a backside-only PDN still flags 'Unconnected
shape' warnings on the tap-cell M1 pins. That requires a first-class
bridge-cell concept (LEF58 extension) and is tracked separately.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
IRSolver::checkOpen seeds its BFS with a single node from the top
routing layer and reports any unvisited node as 'unconnected'. When
the PG network legitimately has more than one component touching the
top layer - notably on a backside-power PDK where the front-side and
backside stacks are stitched only through bridge cells, and each
bridge cell ends up in its own subgraph as seen from the top - the
BFS misses entire subgraphs and reports thousands of spurious
PSM-0038/PSM-0039 warnings.

Seed the BFS from every node on the top layer instead. The cost is
linear in the number of seeds, which is bounded by the number of
top-layer shape pieces, so the overhead is negligible. The visited
flag guarantees we still touch each reachable node exactly once.

This is the third piece of LEF58_BACKSIDE support in PSM (after the
front-side base layer fix in 0e7eabb). On gt2n/gcd with the multi-
port tap LEF, analyze_power_grid now passes connectivity check on
both vdd and vss without any PSM-003x warnings; the IR-drop report
runs cleanly (numbers are zero pending source / power assignment but
the solver no longer aborts).

Asap7 / nangate45 are unchanged: their PG network has only one
component touching the top layer so the multi-seed BFS behaves
identically to the single-seed version.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
…isolated nodes

Adds src/psm/test/check_power_grid_backside.tcl plus a tiny synthetic
backside-power LEF/DEF under src/psm/test/backside_data/. The test
locks in both BSPDN-related PSM fixes:

  * isBackside()-aware ITerm base-layer pick in ir_network.cpp
    (commit 0e7eabb). Without it every ITerm reports PSM-0039
    'Unconnected instance' on this design.
  * Multi-seed connectivity BFS in ir_solver.cpp (commit 6d4c658).
    Without it the BFS misses the BPR-only subgraph and flags
    PSM-0038 'Unconnected shape' on every followpin.

The synthetic LEF declares a routing layer B1 with
LEF58_BACKSIDE BACKSIDE and adds two macros: a bridge_tap with
vdd / vss PINs on both M1 and B1, and a backside_filler with
vdd / vss only on B1. The DEF places two taps and three fillers
on one row with a B1 followpin per net.

Also tightens ir_solver.cpp: when multi-seeding the BFS, a top-layer
seed may be isolated (no LayerConnection built for it) and
connections_map.at(node) used to throw. Switch to find() and skip
isolated seeds; the !isVisited() sweep below already covers
reporting them. Without this guard the new test fires
std::out_of_range on the vss net.

Registered in both CMake (or_integration_tests TESTS) and Bazel
(BUILD COMPULSORY_TESTS + data files for the backside_data dir).

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Adds src/pdn/test/add_pdn_connect_backside_warn.tcl which exercises
the warning added on the bspdn branch (commit b55936a): when
add_pdn_connect is given two layers that disagree on isBackside(),
PDN cannot synthesize a via to bridge them and the connection has to
come from a tap cell. The test calls add_pdn_connect with layers M1
(front) and B1 (LEF58_BACKSIDE backside) and expects PDN-1200 to
appear in the log.

Reuses the synthetic LEF+DEF test fixture under
src/psm/test/backside_data/ so we don't ship a second copy.

Registered in both CMake or_integration_tests TESTS and Bazel
COMPULSORY_TESTS.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>

@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 support for backside layers (such as buried power rails and backside power delivery networks) across ODB, the detailed router (DRT), PDN, and PSM. It ensures that DRT treats backside layers as invisible, adds a boundary-crossing sanity check in PDN, and updates PSM's connectivity analysis to correctly handle backside-power-delivery designs. The review feedback highlights two key improvements: resolving a template iterator type mismatch in the new LEF backside parser, and optimizing a redundant map lookup in the DRT parser's net routing update logic.

Comment thread src/odb/src/lefin/lefTechLayerBacksideParser.cpp Outdated
Comment thread src/drt/src/io/io.cpp Outdated
A PDK cell that physically stitches a front-side power layer to a
LEF58_BACKSIDE-tagged layer (a buried-power-rail tap, basically) can
already be expressed today by giving its VDD / VSS PINs multiple
PORT blocks on the two sides; LEF 5.x semantics make those electric-
ally one node. That convention works for connectivity but does not
let a tool reason about *which* cells are intended as bridges, which
matters for PDN sanity checks, IR-drop source/sink classification,
and tap-cell selection on a BSPDN PDK.

This commit lets the PDK author mark such cells explicitly:

    MACRO bridge_tap
      ...
      PROPERTY LEF58_BACKSIDE_BRIDGE "BACKSIDEBRIDGE ;" ;
      ...
    END bridge_tap

Implementation mirrors the LAYER LEF58_BACKSIDE work earlier in the
series:

  * Adds a 1-bit is_backside_bridge flag to dbMasterFlags (taken from
    spare_bits_19, shrunk to 18).
  * Exposes dbMaster::setBacksideBridge() / isBacksideBridge() via the
    public ODB API.
  * Adds lefMacroBacksideBridgeParser modelled on the existing
    lefMacroClassTypeParser.
  * Wires it into lefin.cpp's MACRO property dispatcher.
  * operator== updated so the flag is included in dbMaster equality.

Registered in CMake (or_integration_tests TESTS) and Bazel
(COMPULSORY_TESTS) with a small standalone Tcl test that reads a
two-cell LEF and asserts isBacksideBridge() = 1 on the tagged cell
and 0 on the untagged one.

No in-tree consumers yet; PDN/PSM tooling that wants to walk PG-net
connectivity across the front/back boundary can now consult this
flag instead of inferring intent from pin geometry.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
@github-actions github-actions Bot added size/L and removed size/M labels May 29, 2026
Comment thread src/pdn/src/pdn.tcl Outdated
Comment thread src/psm/src/ir_network.cpp Outdated
Comment thread src/psm/src/ir_solver.cpp Outdated
Comment thread src/psm/src/ir_solver.cpp Outdated
mguthaus added 5 commits May 29, 2026 07:25
* odb LEF58_BACKSIDE parser: use the template Iterator parameter
  instead of hardcoding std::string::const_iterator in the qi::rule.
* drt updateNetRouting: reuse the iterator returned by find() rather
  than performing a second map lookup.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
A standard cut-layer via cannot bridge a front-side metal to a
backside metal; PDN has no way to create the TSV or backside cut via
that would be needed. Refuse the add_pdn_connect outright instead of
warning and continuing.

Renames the regression test from add_pdn_connect_backside_warn to
add_pdn_connect_backside_err and wraps the offending call in a
[catch] so the harness can still log-compare.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
dbTech now provides first-class accessors for "the lowest front-side
routing layer" and "the lowest backside routing layer", instead of
making every caller walk getRoutingLayerCount() and filter by
isBackside().

Switch PSM's IRNetwork ITerm base-layer pick to use the new helper.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Replace the multi-seed-from-every-top-layer-node workaround with a
proper graph-level fix:

* Pick the iterm base node's layer from the cell's primary side.
  Backside-only cells land on firstBacksideLayer() so their virtual
  base sits on the backside grid instead of dangling on an empty
  front-side rail; front-side and mixed cells keep firstRoutingLayer().
* Introduce BridgeConnection: an explicit zero-impedance virtual edge
  emitted only for cross-side iterm terminals on instances whose
  master is tagged LEF58_BACKSIDE_BRIDGE. Non-bridge cross-side pins
  are intentionally left unlinked, so a malformed PG that relies on a
  non-bridge cell to cross the front/back boundary surfaces as an open
  net instead of being silently stitched together.
* Revert checkOpen() to single-seed BFS. With the explicit bridge
  edges, one seed reaches every legitimately-connected component, and
  the prior multi-seed approach (which could declare disjoint grids
  "connected") goes away. The isolated-seed find()-guard is no longer
  needed.

Updates the backside regression fixture: bridge_tap now carries
LEF58_BACKSIDE_BRIDGE, and the toy M1 stripes (which were not
electrically connected to anything else in the design) are removed -
the test is now a clean BSPDN topology where front/back can only be
crossed through the bridge cell.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
The test was reading the backside fixture via a relative path that
crosses module boundaries (../../psm/test/backside_data/...). That
works under CMake/ctest, but Bazel sandboxes each test and only
exposes files declared as data deps, so the path fails to resolve.

Copy the .lef/.def into pdn/test/backside_data/ and read from there
so the test is self-contained.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
@QuantamHD

Copy link
Copy Markdown
Collaborator

Looks like some of the code modifications you made were not accurately reflected in the python/json generators

  diff --git a/src/odb/src/db/dbTechLayer.cpp b/src/odb/src/db/dbTechLayer.cpp
  index 0e7c7f9323..6aa6303b90 100644
  --- a/src/odb/src/db/dbTechLayer.cpp
  +++ b/src/odb/src/db/dbTechLayer.cpp
  @@ -101,9 +101,6 @@ bool _dbTechLayer::operator==(const _dbTechLayer& rhs) const
     if (flags_.lef58_type != rhs.flags_.lef58_type) {
       return false;
     }
  -  if (flags_.is_backside != rhs.flags_.is_backside) {
  -    return false;
  -  }
     if (wrong_way_width_ != rhs.wrong_way_width_) {
       return false;
     }
  diff --git a/src/odb/src/db/dbTechLayer.h b/src/odb/src/db/dbTechLayer.h
  index 51087b50dc..e04affd25d 100644
  --- a/src/odb/src/db/dbTechLayer.h
  +++ b/src/odb/src/db/dbTechLayer.h
  @@ -70,8 +70,7 @@ struct dbTechLayerFlags
     bool right_way_on_grid_only_check_mask : 1;
     bool rect_only_except_non_core_pins : 1;
     uint32_t lef58_type : 5;
  -  bool is_backside : 1;
  -  uint32_t spare_bits : 3;
  +  uint32_t spare_bits : 4;
   };
   

@mguthaus

Copy link
Copy Markdown
Contributor Author

@QuantamHD Ah, I didn't even realize that was generated code. Fixing the json so it is generated now.

* odb: declare is_backside in the dbTechLayer code-generator schema
  so future regenerations preserve the field, the operator== check,
  and the bit-field packing. The hand-written setBackside / isBackside
  methods continue to live in the existing
  "User Code dbTechLayerPublicMethods" block.

* drt: restore a null-guard around cutLayer->getDefaultViaDef() in
  FlexTAWorker::initFixedObjs. The setLayers filter only removes
  LEF58_BACKSIDE layers; cut layers below MIN_ROUTING_LAYER (e.g.
  contact-layer cuts on PDKs whose MIN_ROUTING_LAYER is well above
  M0) can legitimately have a null defaultViaDef left by
  initDefaultVias and would crash here. Earlier commit message
  claimed the filter superseded the guard; that was wrong - the
  guard is correct in its own right and the filter does not cover
  this case.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Comment thread src/odb/include/odb/db.h Outdated
Comment thread src/odb/include/odb/db.h Outdated
Comment thread src/odb/test/lef58_backside_bridge.lef Outdated
Comment thread src/psm/src/ir_network.cpp Outdated
@QuantamHD

QuantamHD commented May 30, 2026

Copy link
Copy Markdown
Collaborator

Just some food for thought here. Perhaps we should treat back side layers as a 3d chiplet instead of part of the routing layer stack proper. That way we wouldn't have the weirdness of a layer sandwich.

mguthaus added 6 commits May 30, 2026 11:16
When the per-worker grid graph is large (many routing layers × fine
pitch × full-die clip box, as on backside-power PDKs), the product
`xDim * yDim * zDim * 3` used to size `prevDirs_` and index it from
`setPrevAstarNodeDir`/`getPrevAstarNodeDir` exceeds INT32_MAX. With
plain `int` math this wraps negative, causing `prevDirs_.resize()` to
throw `std::length_error` from `vector<bool>::_M_fill_insert` and
detailed routing to crash before the first iteration. Promote the
multiply to `std::size_t` so the capacity and per-node base index stay
correct for grids up to size_t.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
dbBlock::getGCellTileSize() reads track spacings of the 2nd/3rd/4th
routing layer via dbTech::findRoutingLayer(), assuming those indices
hit the lowest signal metals (M2/M3/M4). On PDKs with backside power
(BSPDN) the LEF orders BRDL/BM*/BPR routing layers first, so those
indices instead pick coarse backside metals and the resulting tile
size is roughly 30x too large. That collapses the GCell grid to a
handful of cells, gives detailed routing one die-sized worker, and
indirectly trips the FlexGridGraph capacity overflow.

Walk getLayers() and count only non-backside routing layers so the
heuristic targets frontside signal metals regardless of LEF ordering.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
setLayers() already drops backside routing/cut layers from frTech, so
any block via whose cut/top/bottom layer is on the backside has no
matching frLayer and triggers DRT-0097/0098/0099 ("Cannot find ...
layer") during global routing. Detect such vias up front (via params
and via boxes both) and skip them, mirroring the existing backside
guards elsewhere in this file.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Rename `firstRoutingLayer()` / `firstBacksideLayer()` to
`firstFrontsideRoutingLayer()` / `firstBacksideRoutingLayer()` so the
side filter is explicit in both names and "routing" is consistent.

By PDK convention, backside metals are numbered going away from the
substrate (e.g. BM1 nearest, BM4 farther out, BRDL outermost), mirror-
ing the front-side numbering. In the LEF, however, the backside stack
is listed in physical stack order from the outermost backside layer
down (BRDL ... BPR) before the frontside (M0 ... RDL). Iterating
`findRoutingLayer(level)` from level 1 upward therefore landed on the
outermost backside layer, which is the opposite of what callers (PSM)
need: they want the backside layer closest to the substrate.

`firstBacksideRoutingLayer()` now iterates top-down and returns the
substrate-closest backside layer (e.g. BPR on the bspdn gt2n PDK).
Header doc updated to make that explicit.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Use the new `firstFrontsideRoutingLayer()` / `firstBacksideRoutingLayer()`
names. Remove the defensive fallback that reassigned `front_base` to
`findRoutingLayer(1)` when no front-side layer was found. That branch
only triggered while the LEF backside flag wasn't being parsed (every
layer reporting `isBackside()=0`); with the parser correctly hooked up
in odb, a tech that legitimately has no front-side routing layers is
not a real configuration. Letting `front_base` stay null surfaces a
clear caller-side error instead of silently substituting a backside
layer as the front-side base node.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Built-in LEF58 properties are dispatched by a hardcoded name table in
the LEF reader (lefin.cpp) and do not require an explicit
PROPERTYDEFINITIONS statement; matching the style of existing tests
for LEF58_BACKSIDE, LEF58_RECTONLY, etc. Verified that the parser
still picks up LEF58_BACKSIDE_BRIDGE on `bridge_tap` and the .ok
golden still matches.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>

@mguthaus mguthaus left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've confirmed that this works on gcd and aes (which I have running on a soon-to-submit PR to ORFS). There are some integrated changes to fix the DRT routing grid and worker sizing which became a problem because of the DBU sizes in some of the back-side layers. However, those designs will work correctly now when I submit this PR and the later fixes.

@mguthaus mguthaus marked this pull request as ready for review May 30, 2026 19:33
@mguthaus mguthaus requested review from a team as code owners May 30, 2026 19:33
@mguthaus mguthaus requested a review from maliberty May 30, 2026 19:33

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

Only reviewing PDN/PSM

Comment thread src/psm/src/ir_network.cpp Outdated
Comment thread src/psm/src/ir_network.cpp Outdated
Comment thread src/pdn/src/pdn.tcl Outdated
mguthaus added 2 commits May 30, 2026 12:56
Use the dbBox's tech layer directly instead of running every pin
geometry through generatePolygonsFromBox(); we only need to know
which side(s) of the stack the pin sits on, so the per-shape polygon
math and the instance transform are unnecessary. Also reach the
master via inst->getMaster() instead of iterm->getMTerm()->getMaster()
since inst is already in scope.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
The check that refused connect rules spanning the front-side/backside
boundary lived only in the add_pdn_connect Tcl command. Moving it into
Connect::Connect() makes it catch every PDN connect rule regardless of
how it was constructed (Tcl entry point, programmatic API, future
callers), which matches the underlying invariant: PDN can never bridge
the two sides via a cut-layer via, so any such rule is wrong wherever
it originates. Tcl-side duplicate guard removed.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
@mguthaus mguthaus requested a review from gadfort June 1, 2026 23:47
mguthaus added 2 commits June 2, 2026 10:16
Auto-applied by buildifier (format + lint=fix) to satisfy the
Buildifier format / Buildifier lint GitHub-Action checks on PR The-OpenROAD-Project#10547.

- src/psm/test/BUILD: move backside_data/backside.{def,lef} into
  alphabetical position within the data filegroup.
- src/pdn/test/BUILD: move the add_pdn_connect_backside_err key into
  alphabetical position within the per-test data dict to clear the
  unsorted-dict-items warning at line 295.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
Clears the remaining Clang-Tidy-Bazel warnings introduced by the
LEF58_BACKSIDE PR (The-OpenROAD-Project#10547):

- src/drt/src/io/io.cpp:480: change the loop index in the
  backside-via-skip path in setVias() from `int i = 0; i < (int)
  via->getViaLayerRuleCount()` to `uint32_t i = 0; i <
  via->getViaLayerRuleCount()` to match the API return type and
  silence modernize-use-integer-sign-comparison.

- src/drt/src/io/io.cpp:1068: mark updatefrAccessPoint static. It
  is only invoked from within this TU (line 1209 and 1299); the
  return-type change from void to bool on the bspdn branch made
  clang-tidy re-flag misc-use-internal-linkage.

- src/odb/src/lefin/lefTechLayerBacksideParser.cpp: wrap the
  template parse() helper in an unnamed namespace inside
  odb::lefTechLayerBackside so the helper has internal linkage.
  The public entry odb::lefTechLayerBacksideParser::parse() still
  resolves through lefTechLayerBackside::parse() because the
  unnamed namespace is implicitly part of its parent for qualified
  lookup.

No functional change. Local build + odb.lef58_backside_bridge.tcl
golden test both clean.

Signed-off-by: Matthew Guthaus <mrg@ucsc.edu>
@maliberty

Copy link
Copy Markdown
Member

@gadfort are your concerns resolved?

@maliberty maliberty merged commit e03cf07 into The-OpenROAD-Project:master Jun 4, 2026
16 checks passed
@maliberty

Copy link
Copy Markdown
Member

@mguthaus do you have plans for how bridge cells will get inserted?

@mguthaus

mguthaus commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

@maliberty In the GT2N PDK, the "TSV" is a nano-TSV built inside each standard cell during virtual fabrication: BPR -> 2 nm via -> S/D Wrap-Around Contact, so the cell's vdd/vss pin already sits on BPR and the chip-level PG never leaves the backside stack. ORFS mirrors this (I will submit this to ORFS today or tomorrow) which builds only a backside grid (BPR followpins -> BM1/BM2 mesh) and lets the followpin shapes overlap each cell's BPR pin directly, so PDN places no chip-level TSV by design. The LEF58_BACKSIDE_BRIDGE / BridgeConnection plumbing in this PR is there to support hybrid front+back PG flows in the future; on stock GT2N it stays dormant since there's no frontside PG to bridge to. The tap cells right now have both back-side and front-side connections, so these could be used to make a hybrid front+back now to mitigate any issues before we get a PDK that requires it though. Then we will need to think about tap placement for PDN IR drop.

@maliberty

Copy link
Copy Markdown
Member

How does the power from the package reach the backside in GT2N?

@mguthaus

mguthaus commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

C4 bonds on the backside through the backside RDL layer.

@maliberty

Copy link
Copy Markdown
Member

Is C4 on both side or should I reverse the question and ask how signals reach the front side?

@mguthaus

mguthaus commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Presumably the signals on the front side would reach through a pad frame. The PDK doesn't solve this issue and doesn't provide area IO or perimeter IO libraries.

@gadfort

gadfort commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

@mguthaus I'm getting this:
[ERROR GRT-0126] Layers BPR and M0 have the same preferred routing direction (HORIZONTAL).
When I tried to run and the global routing congestion heatmap opens, how did you get around this?

@mguthaus

mguthaus commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

@gadfort I didn't see this in any of my runs. How are you getting this? My tests are in this other branch of ORFS
The-OpenROAD-Project/OpenROAD-flow-scripts#4277

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.

4 participants