Skip to content

X5: LEF/DEF, PEX and flow rows - #35

Closed
OmarSiwy wants to merge 15 commits into
verification-hardeningfrom
agent/x5
Closed

OmarSiwy wants to merge 15 commits into
verification-hardeningfrom
agent/x5

Conversation

@OmarSiwy

Copy link
Copy Markdown
Contributor

Round 2 of X5: the PEX and FLOW rows still partial or missing. First: a LEF/DEF 5.8 reader (gpurify_ingest::lefdef) so a DEF layout runs through every check; more rows follow commit by commit.

@OmarSiwy OmarSiwy added the heavy Run the nightly test tier on this pull request label Oct 12, 2026
GPurify read GDSII only, so a placed-and-routed design could not be
checked or extracted from its LEF/DEF, which FLOW-003, FLOW-004 and
PEX-014 need.

gpurify_ingest::lefdef reads the LEF/DEF 5.8 subset that draws
geometry: LEF units, layers (type, width, pitch, direction), fixed and
generated vias with cut patterns, sites, non-default widths and macro
abstracts; DEF units, die area, rows, tracks, vias, non-default rules,
components, pins, regular and special nets (wires with their
extensions, vias, via arrays, RECT, VIRTUAL, POLYGON) and fills. What it
does not model (LEF PATH/ITERATE, STYLE, 45-degree wires, SHIELD,
SUBNET) is refused with its line. `flatten` places every shape with its
net; `to_gds` writes them as GDSII on the deck's layers of the same
names, with each net's name as a label, so the GDS reader, derived
layers and label binding take a DEF as any layout. `gpurify <cmd>
top.def --lef tech.lef --lef cells.lef --deck d` runs it.

Tests (oracles): the reference's own examples (Example 4-36 and Figures
4-25 to 4-27 for generated vias, Figures 4-31/4-32 for cut patterns,
the p. 269 extension example, Example 4-12 for VIRTUAL and RECT), every
orientation hand-derived from the p. 244 placement rule, a GDS round
trip, and an end-to-end DEF wire against R = Rs L/W and C = Ca A + Cf P.
A new fuzz target `lefdef` replays its seeds on stable. Breaking the
half-width default extension, an orientation or the via offset fails
the matching example test.
…s (X5)

A differential for gpurify_ingest::lefdef: 200 seeded designs (every
macro orientation with an ORIGIN, polygon pins, obstructions, regular and
special wires with default and explicit extensions, fixed and generated
vias with a cut pattern, origin and offset, via arrays, pins in every
orientation, fill) drawn by GPurify and by KLayout's LEF/DEF reader,
compared per layer by the merged XOR area, which must be 0. It runs in
the oracles job (tests/klayout) and is skipped by name in the plain
ignored job. A merge-tier test holds the generator to what the reader
reads, so the differential compares drawings, not refusals. An
orientation or extension that differs from KLayout's fails it.
…y name (X5)

PEX-009 was library only: compare took two extractions of one layout,
matched by net id, with no reader for another tool's netlist and no
command line.

gpurify_extract::foreign reads SPEF (IEEE 1481 *D_NET form: units, name
map with escapes, triplets as their typical value, *CONN drivers,
*CAP/*RES/*INDUC) and DSPF (*|NET sections, SPICE cards with scale
suffixes and continuations) into a ParasiticNetwork on sorted net names;
Read::on_names puts two files on the union of their names (PEX
Certify's "PEX Link"). A coupling listed in both nets' *CAP sections, the
usual form, counts once. Reduced and physical nets are refused.
`gpurify compare <ref> <cand> [--tolerance p]` prints the five metrics'
statistics and exits 0 only when every row is within the tolerance and
both files hold the same nets. A new fuzz target `spef` replays the
seeds and every golden SPEF/DSPF.

Tests (oracles): hand-derived values from a SPEF in PF/KOHM with a name
map, triplets and a doubly listed coupling (2.5 and 1.1 fF, 75 ohm from
the driver); a DSPF with suffixes and a continuation; a round trip of
the writers' own SPEF and DSPF; a CLI case 10 % off that fails at 5 %
and passes at 20 %. Counting the doubly listed coupling twice, or
reading a triplet's first value, fails them.
…locks' abstracts (X5)

FLOW-003 and FLOW-004 were missing: GPurify had no placed-and-routed
design to check them on.

With a DEF layout, DRC now runs six integration checks
(gpurify::engine::integration), each from LEF/DEF 5.8: a FILLS shape
outside the DIEAREA, a component outside it, two placed components
overlapping (CLASS COVER aside), a CORE cell off its ROW's sites, a DEF
pin whose centre is on no TRACKS of its layer, a vertex off the LEF
MANUFACTURINGGRID. Loaded carries the design (Def and Lef) for them. The
DEF's blocks are drawn as their LEF abstracts, so the deck's rules check
top-level routing against block pins and obstructions: interface DRC.
Macro synchronisation (a macro's GDS against its abstract) is not done.

Tests (oracles): construct-from-answer, one or two faults planted per
integration check by its definition, with its examined count; a hand-
derived containment case where a box bridging a U-shaped die's notch has
all four corners inside (the crossing test catches it); a top-level met2
wire 0.1 um from a block obstruction breaking a 0.2 um spacing. Dropping
the edge-crossing test or the COVER exemption fails them.
Page numbers and quotes for CLASS COVER (p. 114), ROW (p. 299), TRACKS
(p. 336) and MANUFACTURINGGRID (p. 148), read off the reference.
…eck says (X5)

PEX-012 was missing: a fill piece extracted as an unlabelled net of its
own, so a SPEF of a filled design was refused and its coupling never
reached the nets around it.

A deck line `pex_fill <layer> floating|grounded|ignored` marks a
conductor as fill; the treatment is the foundry's choice and the deck's
to state. gpurify_extract::fill folds every net drawn only on fill layers
into the rest of the network: floating pieces are eliminated by Kron
reduction of the nodal capacitance matrix (a cluster of coupled pieces
at once, a dense Cholesky solve capped at 2048 pieces), grounded ones
turn couplings into ground capacitance, ignored ones are dropped; the
fill's nets leave the output. The deck carries the line through parse,
print, compile and decompile as PexModels, the place later PEX models
go.

Tests (oracles): closed forms. One floating piece puts c1 and c2 in
series with its own ground c_g (c1 c2 / (c1 + c2 + c_g)); a chain of two
pieces between three 3 fF capacitors is 1 fF; a grounded piece grounds
2 and 3 fF; a floating piece next to a grounded one is 1 fF to ground.
End to end, a fill plate between two 10 x 10 um plates in k = 3.9 adds
C1/2 in series to the C1/3 direct coupling, or grounds C1 on each side.
Counting a coupling once per end, or dropping the elimination's ground
term, fails them. The KLayout LEF/DEF differential now reads its rows
from a file: KLayout's warnings share stdout.
…come from the deck (X5)

PEX-011 was missing: the capacitance inside a transistor that its SPICE
model leaves to extraction comes from the foundry's device cross-section,
which no open PDK publishes.

A deck line `pex_device "<model>" gate_contact_cap <c> gate_diffusion_cap
<c>` states both per um of gate width (required, no defaults);
gpurify_extract::device_region adds (gate_contact + gate_diffusion) * W
from each such MOS's gate net to its source net and to its drain net (a
finger has one source and one drain side, so any finger split totals W
a side). Trench-contact and gate-position resistance are not placed: the
network has no node inside a device.

Tests (oracles): metamorphic against the run without the line, the
difference exactly 2 * 0.5 aF/um * W over the inverter's nfets and none
for its pfet; the deck line survives printing (round trip) and is
refused for a model no `device mos` declares, a missing key, a fill
layer that carries no net, an unknown treatment. Applying the
coefficient once per device instead of per side halves the difference
and fails it.
… it (X5)

The KLayout differential and a new OpenROAD one disagreed with the
reader on three things, and the reference and OpenDB settle each:

- a point's extension also starts the wire that leaves the point on the
  via's other layer (`( x y 30 ) VIA12 VIA12 ( x2 * )` extends the next
  M1 segment by 30); the reader dropped it at the via. OpenDB keeps it,
  so the reader now does.
- a special wire turning a corner with no extension: each segment is
  its own rectangle (LEF/DEF 5.8 p. 321; OpenDB), the corner square
  undrawn; KLayout joins the path. The reader stays with the reference.
- KLayout cuts a whole path square at a short last move with a short
  extension, and draws a stated extension after a via with no wire
  after it; OpenDB and the reference do neither.

tests/exhaustive/lefdef.rs compares every special net of 100 seeded
designs (corners, extensions anywhere and after vias, via arrays) box
for box with OpenDB's dbSBox list; it runs in the oracles job and is
skipped by name in the plain ignored job. The KLayout differential's
generator keeps to geometry the two tools draw alike (straight special
wires, extensions on long last moves, a via's extension only before a
wire), and the LEF gains the VIARULE GENERATE rules OpenROAD needs. A
reader that drops the carried extension fails 5 of the 100 designs.
…een two nets are reported (X5)

PEX-016 was missing: ERC measured point-to-point resistance only
between a net's device attach points, on an ESD path, and nothing
reported coupling between two named nets.

erc::power::extract_points_into builds one net's resistor network (the
p2p_resistance chain model: each conducting shape a chain along its
long axis, sheet times squares, each cut its layer's resistance) with a
terminal at each given point, refusing a point on none of the net's
conducting shapes; gpurify::engine::p2p reduces it to the points'
pairwise effective resistance and sums the coupling between two nets in
the extracted network. `pex --p2p NET:X,Y:X,Y... --coupling A:B` adds
both to the text report.

Tests (oracles): closed forms on two parallel 0.2 um DEF wires 0.8 um
apart: 25 ohm between x = 10 and 60 um at 0.1 ohm/sq, 0 from a point to
itself, eps0 k t L / S of coupling; a point off the net and an unknown
net are refused; the command line's forms and refusals. Tapping the
nearest shape instead of the one holding the point fails the refusal.
…orm's end fringe (X5)

PEX-014 (route-level extraction from LEF/DEF) was missing for want of a
DEF reader; with gpurify_ingest::lefdef a DEF's wires, vias and pins are
drawn on the deck's layers and extracted like any layout.

tests/exhaustive/pex/openrcx.rs runs OpenROAD's extractor with LEF RC
(`extract_parasitics -lef_rc -version 2`; the default version asks for
an extraction rules file even with -lef_rc) on 30 seeded DEFs of
straight two-pin wires whose LEF RPERSQ/CPERSQDIST/EDGECAPACITANCE are
the deck's sheet/area/fringe, reads its SPEF back with
gpurify_extract::foreign, and holds every net to it: R equal (both read
RPERSQ L/W with the half-width extensions in L) and C equal plus
2 W fringe_cap, the two wire ends OpenRCX leaves out, each to the SPEF's
printed digits. M1 and M2 nets are kept from crossing: OpenRCX with LEF
RC extracts no interlayer coupling, the closed forms do (the first run
found 2.3 aF at each crossing). In the oracles job; skipped by name in
the plain ignored job.

FLOW-010 rides along: `--cluster <um>` lists each rule's violations in
single-linkage clusters (gpurify::engine::triage), checked against a
hand-derived chain and a brute-force flood fill on 40 seeded tables.
… base (X5)

After the rebase onto H13's `gpurify system`: the system command line
carries the new Cli fields (no --p2p, --coupling or --cluster for it:
its report is its own), and check-sources.md's generated block follows
X5's rows over the base's, regenerated by tests/catalog.rs.
… form's laws (X5)

Testing-plan F6's open half: the PEX corpus ran only the closed forms,
so the field solver met none of its cases.

common::check_pex_case_field_solved runs each case with every labelled
net named for the field solve and holds it to what the closed forms and
the solve's laws say: the case's stage outcome and drawn nets; a
resistance case with a derived closed form agrees with it to the case's
tolerance (a straight bar is Rs L / W in both, and the negative cases
still disagree); a coupling case is finite and at least the closed
form's value, which leaves out every fringing field; a ground
capacitance is finite and positive (the deck's area and fringe
coefficients are not derived from the stack, so nothing bounds the
field's). All 27 cases pass; on the first run the field solve read
1.4 to 20 times the closed form's coupling, and the filament R matched
Rs L / W to 1e-15. Swapping the field and closed-form values of a
coupling case, or a filament R off by a square, fails it.
The base's new tests/drc_octilinear.rs builds a Loaded by hand; it gains
the design field X5 added (None: its layout is no DEF).
…he deck states it (X5)

PEX-015 (3D-IC extraction) was missing: no open PDK has a TSV, so no
deck could say what one is.

A deck line `pex_tsv <cut layer> length <l> liner <t> liner_k <k>`
(every value required) marks a `connect via` cut layer as through-
silicon vias; gpurify_extract::tsv gives each cut, a copper cylinder of
its drawn area's radius, the liner's capacitance to the grounded silicon
2 pi eps0 k l / ln((r + t) / r) (Katti et al., IEEE TED 57(1), 2010,
eq. 2) on its net; its resistance is the pex row's per cut. Not
modelled: depletion in series with the liner, TSV-to-TSV coupling
through the silicon, micro-bumps, interposer wiring.

Tests (oracles): closed form, two 5 x 5 um TSVs 50 um long in a 0.2 um
k = 3.9 liner on one DEF net give twice the coaxial value to 1e-9; the
deck line survives printing and is refused on a layer that is no cut
and without liner_k. Using the cut's half side instead of the area's
radius fails the closed form.
@OmarSiwy

Copy link
Copy Markdown
Contributor Author

Landed on verification-hardening (rebased; proving tests registered; workspace tests run locally).

@OmarSiwy OmarSiwy closed this Oct 12, 2026
@OmarSiwy
OmarSiwy deleted the agent/x5 branch October 12, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

heavy Run the nightly test tier on this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant