Skip to content

vyges-tools/lvs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vyges-lvs

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-lvs opens 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.

Why this exists

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.

How this is solved today

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.

The job (.lvs)

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/--version

How it compares

The 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).

Domain coverage — digital and analog / mixed-signal

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).

Native extraction (Phase 2) — vyges-layout

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 schematic

examples/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).

Open core, certified fab plugins

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.

Current state

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".

For researchers — open problems

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).

  1. 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_series in compare.rs (run to a fixed point by normalize) — add the new reduction passes there.
  2. 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_iso in compare.rs — add canonical-form / individualization-refinement (à la graph-isomorphism research), with scaling data.
  3. 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_wl in extract.rs — add passive-device recognition + value extraction the same way.
  4. 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_props in compare.rs — replace the flat 1 % with a per-PDK / statistical model.
  5. 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 flatten pass in spice.rs — match at .subckt boundaries instead of fully expanding.
  6. 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 + unbalanced report in compare.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.