Layout-vs-schematic netlist comparison: two SPICE netlists in — a layout-extracted one and the schematic/reference — a MATCH / MISMATCH verdict with clear divergence diagnostics out.
Vyges open EDA tools. Commercial-grade silicon sign-off capability, built on open standards and plain file formats — meant to be accessible to everyone, not only teams who can license a six-figure tool.
vyges-lvsopens up LVS.
Docs: docs.vyges.com — this engine's chapter, the
cross-engine integration guide, and the
job-file formats. In-repo depth: docs/engines-integration.md. Integrating at the binary
level and need help? → https://vyges.com/contact.
A layout is only correct if it implements the schematic — same devices, same connectivity. LVS proves that by matching the two netlists as graphs, independent of how nets and instances happen to be named. When they don't match, the only thing that matters is where they diverge — and that is exactly where the open incumbent is weakest.
In production, LVS is one of the commercial LVS tools — gated
behind major licenses. The open baseline is Netgen (used in the sky130 flow):
correct, but its divergence output is famously cryptic, so debugging a mismatch is
slow. vyges-lvs is an open engine in that space, behind plain SPICE, that leads
with readable diagnostics — the unmatched devices and nets, named.
Describe the job, not the script. A small declarative .lvs file — readable,
diffable — instead of a tool-specific rule script.
layout: block_layout.spice # the layout-extracted netlist (side A) …
# … OR extract the layout natively from a GDS (Phase 2):
layout_gds: block.gds # layout geometry
rules: block.rules # layer roles for extraction
schematic: block_schematic.spice # the reference / schematic netlist (side B)
top: block # subckt to compare (optional; else top-level)
cargo build --release # std-only, no external deps
vyges-lvs run examples/inv_chain/match.lvs # -> MATCH
vyges-lvs run examples/inv_chain/mismatch.lvs # -> MISMATCH + diagnostics
vyges-lvs run examples/inv_chain/mismatch.lvs --fail-on-mismatch # exit 3 (CI gate)
vyges-lvs run examples/inv_chain/match.lvs --json # machine-readable
vyges-lvs demo # built-in pair, no files
# common flags: -o FILE · --json · -q/--quiet · -v/--verbose · -h/--help · -V/--versionThe SPICE reader flattens hierarchy: every X subckt instance is expanded to
primitive devices (formal ports bound to the actual nets at the call site, internal
nets uniquified per instance, .global and node 0 kept global). The compare therefore
runs at transistor level, not as a cell-by-cell connectivity check — two layouts that
instantiate the same cells but wire their internals differently now diverge.
Matching is name-independent graph colour-refinement (1-WL) on the device/net bipartite graph: a device's colour folds in its kind/model and its terminals' net-colours (in order); a net's colour folds in the multiset of (device-colour, terminal-position) it touches. Refined to a fixed point on the disjoint union of both netlists, the two sides balance iff every colour class balances. Supply/global nets are held at a fixed colour so a single local fault stays local instead of cascading across the power rail, and unmatched classes are reported smallest-first so the offending device/net is named at the top of the report. Ports are anchored by name (the boundary aligns); internal nets match purely by structure.
1-WL balance is necessary but not sufficient (it can't separate certain symmetric
graphs), so a balanced result is then confirmed by constructing an explicit device/net
bijection — iterative, heap-stacked backtracking that is S/D-symmetry aware. A true
MATCH is reported as verified; a colour-refinement false positive is refuted. SPICE
reader handles .subckt/.ends, .global, + continuation, comments, and M/Q/R/C/L/D/X
devices.
Device parameters are checked, not just topology. The reader captures MOSFET w/l
(and nf/m) and the value of an R/C/L (SPICE engineering suffixes resolved). The
bijection is required to pair only parameter-compatible devices (1% relative tolerance);
when topology matches but a parameter doesn't, the verdict is a parameter mismatch that
names the device and the offending parameter — a transistor drawn at the wrong width is a
real LVS error a connectivity-only check passes. Only parameters present on both sides are
compared, so a netlist that omits a default never forces a false mismatch.
Source/drain are matched symmetrically (a MOSFET's S/D are interchangeable); bulk is matched (gate and bulk positional).
The compare is device-kind-agnostic: it matches the netlist graph, seeded only by each
device's kind/model, over the generic SPICE primitives M/Q/R/C/L/D/X. Nothing in the path
assumes standard cells, Liberty, or a clocked digital netlist — so vyges-lvs runs on
analog and mixed-signal blocks exactly as it does on digital ones (the only kind-specific
rule is electrically-correct MOSFET S/D symmetry, which analog needs too).
- Digital:
examples/inv_chain/— a standard-cell inverter chain. - Analog:
examples/bandgap/— a bandgap reference exercising bipolar transistors (Q), resistors (R) and a capacitor (C) alongside a PMOS mirror (M).match.lvs→ MATCH on a renamed/reordered layout;mismatch.lvs→ MISMATCH on a mis-wired sense resistor (the miswire breaks a private series node, so the schematic's two series resistors combine while the bug's do not — caught as a resistor-count divergence).
vyges-lvs run examples/bandgap/match.lvs # -> MATCH
vyges-lvs run examples/bandgap/mismatch.lvs # -> MISMATCH (mis-wired R, named)Mixed-signal scope here is physical connectivity (LVS); analog functional/timing sign-off is out of scope (it leans on external SPICE/behavioral tools).
vyges-lvs can extract the layout netlist from a GDS itself, using the vendored
geometry kernel (vyges-layout): devices are
gate∩active (poly AND active), type from nwell, source/drain from active − poly, bulk
from the nwell net (pfet) or the substrate net (nfet). Connectivity is contact-gated —
shapes on different layers join only where a contact: shape overlaps both, so a gate
abutting its source/drain is not shorted to them — and net names come from TEXT labels.
A small .rules file maps layer roles + contacts (per-PDK; the NDA-plugin boundary):
vyges-lvs extract block.gds --rules block.rules --top block # GDS -> SPICE
# or in a job: layout_gds: + rules: -> extract then compare to the schematicexamples/inv/ is a worked inverter: inverter.gds extracts to 2 transistors
(nfet + pfet, correct bulk) and matches schematic.spice. On a real sky130 cell
(sky130_fd_sc_hd__inv_1), extraction is net-level identical to Magic's golden netlist
(full LVS MATCH, hvt included); on a 28-T flop (dfrtp_1) the topology matches Magic
(28 devices, 21 nets); and on a placed-and-routed multi-cell block (the counter through
OpenLane, 229 cell instances) it flattens + extracts ~600 transistors end-to-end — see
correlation/.
It also recovers each transistor's gate W/L from the channel geometry — the channel extent along the source→drain axis is the length, the perpendicular extent the width — so the comparator's property audit checks drawn dimensions straight from the layout (a MOSCAP's tied diffusion has no defined W/L and is skipped).
The extractor handles hierarchy (SREF/AREF flattened first), metal-to-metal vias
(just more contact: rules), and enclosure-gated contacts (a contact joins two layers
only where it is enclosed by a shape on each). Same-layer connectivity is true geometric
overlap (shapes tiled into rects, not bounding boxes).
Honest bounds (depth reserved). The comparator flattens hierarchy, anchors supply nets
so a local fault no longer cascades into thousands of spurious classes, and confirms a
balanced match by constructing an explicit bijection (refuting 1-WL false positives); the
remaining depth is performance on pathologically symmetric blocks, where that search is
budget-bounded and reports the symmetry as unresolved rather than guessing.
The extractor (v0): contacts/vias by enclosure (no full DRC), model variants reported as
device type (hvt resolved via marker-layer rules; special_nfet the remaining depth item),
Manhattan boolean — all on the vyges-layout depth path. Net-level LVS parity with Magic holds
on real sky130 cells today (a 2-T inverter exactly incl. hvt, a 28-T flop's topology). On a
placed-and-routed multi-cell block (the counter through OpenLane, 229 instances) extraction
reaches exact device parity with Magic — 842 transistors (421 n / 421 p), including decap
MOSCAPs (source=drain) — in ~1.5 s (release) via a uniform-grid spatial index. Parasitics
are handled by the sibling vyges-extract engine off the same routed layout — the DEF
extracts to standard SPEF (R + coupling C); with a calibrated sky130A deck the total cap
tracks OpenRCX to 0.997, closing the LVS + PEX loop on one block (see
correlation/routed-counter.md).
vyges-lvs is open (Apache-2.0) and contains no foundry-confidential data — it
compares the netlists you supply. Per-PDK device-recognition / extraction decks
(Phase 2, layout-side) ship as separate plugins under that foundry's terms, never in
this repository.
Transistor-level SPICE compare (X-subckt hierarchy flattened) with a MATCH/MISMATCH
verdict, device/net counts, per-kind diffs, and unmatched-class diagnostics — source/drain
symmetric, supply-anchored so a local fault doesn't cascade, and reported smallest-class
first so the fault is named. A balanced match is verified by an explicit bijection (or a
1-WL false positive refuted); the verdict carries a verified flag in text + JSON.
Device parameters (MOSFET W/L, passive value) are checked on the matched bijection to a
1% tolerance, so a wrong-width transistor is reported as a named parameter mismatch.
Parallel and series devices are combined before matching (to a fixed point): fingered
transistors sum their width; parallel R/L and series C combine reciprocally; series R/L and
parallel C add — so an N-finger layout matches a single wide schematic device, and a passive
chain through private internal nodes matches one lumped device. Native GDS extraction
(Phase 2, via the vendored vyges-layout kernel); a --fail-on-mismatch CI gate. Pure std,
unit + example tested offline, no subprocess.
Depth still reserved on the comparator: passive values from layout geometry (R/C drawn dimensions, the way MOSFET W/L already is), and reductions beyond simple series/parallel (bridge / delta-Y networks).
Verdict-parity correlated against Netgen on a real sky130 block (see
correlation/): on a synthesized sky130 counter (23 cells), vyges-lvs
and Netgen agree 3/3 — MATCH on a renamed/reordered netlist, MISMATCH on a dropped cell
and on a swapped net — with vyges-lvs naming the unmatched device/net classes where
Netgen prints a terse "do not match".
vyges-lvs is a compact, std-only, fully open comparator with a real correlation harness
against Netgen — a good base for student research in physical verification. Each item is a
self-contained, publishable direction; the SPICE-in / verdict-out boundary lets a new
method drop in and be measured against the existing baseline.
Several already have a working baseline you can build straight on top of — each item names the code anchor (the file / function that is the foundation and the natural drop-in point).
- General network reduction. Parallel and simple series chains are merged; extend to
arbitrary series-parallel and bridge (delta-Y) passive networks, and to recognized
transistor-stack patterns. Start from:
combine_parallel/combine_seriesincompare.rs(run to a fixed point bynormalize) — add the new reduction passes there. - Symmetric-graph resolution at scale. The match is 1-WL + bounded backtracking; on
highly symmetric structures the search is budgeted and reports unresolved. Start from:
the iterative backtracker
verify_isoincompare.rs— add canonical-form / individualization-refinement (à la graph-isomorphism research), with scaling data. - Passive values from layout geometry. MOSFET W/L are now extracted from the channel
geometry during native extraction; extend this to passive values (resistor sheet count,
capacitor area) and to non-rectangular / multi-finger channels. Start from:
channel_wlinextract.rs— add passive-device recognition + value extraction the same way. - Tolerance & corner-aware property checks. Per-PDK and statistical parameter tolerances,
binning, and corner-aware comparison — what counts as "the same device" at an advanced node.
Start from:
PROP_TOL+props_compatible/audit_propsincompare.rs— replace the flat 1 % with a per-PDK / statistical model. - Hierarchical LVS. Compare at subckt boundaries without full flattening, for block-level
scale — and study the speed/accuracy trade-off vs. the flat compare. Start from: the
flattenpass inspice.rs— match at.subcktboundaries instead of fully expanding. - Diagnostics quality. Better localization and ranking of the root-cause device/net in a
large mismatch (beyond smallest-class-first) — a usability problem with measurable metrics.
Start from: the class sort +
unbalancedreport incompare.rs.
Working on one of these — or want to? We're actively pursuing several of these areas
ourselves, but the open frontier is bigger than any one team, and we'd rather build it in
the open than wait. If an item here fits your research, a student project, a thesis, or just
an itch, we'd genuinely like to hear from you — open an issue, send a PR, or reach us at
https://vyges.com/contact. Promising directions become collaborations; the correlation/
harness makes before/after numbers easy to report in a paper.