Skip to content

lvs: three defects that made gf180 report the wrong answer - #119

Open
jeffhsu3 wants to merge 4 commits into
ReaLLMASIC:mainfrom
jeffhsu3:lvs-harness-fixes
Open

jeffhsu3 wants to merge 4 commits into
ReaLLMASIC:mainfrom
jeffhsu3:lvs-harness-fixes

Conversation

@jeffhsu3

Copy link
Copy Markdown

Branch: lvs-harness-fixes → main · 4 commits · no layout changes

Three independent bugs in the LVS harness, each of which made gf180 report
something other than the truth. None of them touch a cell's geometry.

1 & 2 — .subckt default params break the gf180 deck

KLayout's SPICE reader folds a subcircuit's default parameters into its name.
So a netlist emitting

.subckt two_transistor_interdigitized VDD1 VDD2 VSS1 VSS2 VG1 VG2 VB l=0.28u w=3u m=1

is read back as the circuit TWO_TRANSISTOR_INTERDIGITIZED(L=0.28U,M=1,W=3U).
The gf180 deck then cannot match it to the layout's top cell and aborts:

ERROR: Can't find a schematic counterpart for the top cell two_transistor_interdigitized

_parse has no branch for that string, so it falls through to the catch-all
"LVS inconclusive" with unmatched_nets: 0 — which reads as "0 mismatches".
There genuinely were zero comparisons, not zero errors. Extraction itself was
fine; the .cir had every device.

Two cells were affected. two_transistor_interdigitized's device lines already
carried l/w/m explicitly so the defaults were dead weight; the converter's
body referenced them (l={l} w={w} m={mt}), so the values are inlined instead.
Both netlists are electrically identical afterwards.

transmission_gate was never affected — its top-level .subckt carries only
node names. Its inner NMOS/PMOS subckts do have params and get the same
parenthesised names, but they are not the top cell and match structurally.

3 — gf180 was extracting the wrong MIM stack

gf180 has two mutually exclusive MIM stacks. glayout builds option B
(mimcap and mimcap_array both default to option="B", met4/FuseTop/met5),
but the runner extracted option A (met2/FuseTop/met3). Extracting A against a
B layout yields no capacitor at all:

[FAIL] opamp: 1 schematic device(s) missing from layout, first 1.2.0.1 [CAP_MIM_2F0FF]

The capacitors were always present — opamp.gds carries FuseTop (75/0) ×6 and
MIM_L_MK (117/10) ×6 alongside Metal4/Metal5, six of each matching the six
MIMCap instances. $GF180_MIM_OPTION still overrides.

The --mim-option flag already existed and was documented, but
.github/workflows/lvs.yml never passed it, so CI has been extracting the wrong
stack for every gf180 cell with a MIM. Fixing the default means the workflow
needs no change.

Result

Full DRC + LVS, both PDKs, measured on this branch off main:

before after
gf180 opamp FAIL, two_transistor_interdigitized inconclusive 19 pass, 0 fail
sky130 18 pass, opamp 1 mismatch 18 pass, opamp 1 mismatch

The remaining sky130 opamp failure is pre-existing and unrelated — Magic
mis-extracts the PMOS bulk of differential_to_single_ended_converter (the
documented reason that cell is on the default --skip-cells list), which strands
two pfet source/drains off the inter-stage net. gf180 extracts the same source
layout as connected. Not addressed here.

Also included: tests: rebuild stale venvs in the local CI bootstrap, a
dev-tooling fix to run_ci_locally.py.

Follow-up worth doing separately

_parse should get an explicit branch for "Can't find a schematic counterpart"
so a name mismatch stops reporting as the catch-all. It cost two diagnoses.


🤖 Generated with Claude Code

https://claude.ai/code/session_01RExJUxLyBEHcQRb6GprVSL

jeffhsu3 and others added 4 commits August 30, 2026 09:39
KLayout's SPICE reader folds a subcircuit's default parameters into its NAME:
`l=0.28u w=3u m=1` turns the circuit into
`TWO_TRANSISTOR_INTERDIGITIZED(L=0.28U,M=1,W=3U)`, after which the gf180 klayout
deck cannot match it to the layout's top cell and aborts with "Can't find a
schematic counterpart for the top cell".

The device lines carry l/w/m explicitly, so the defaults on the .subckt line were
never used. sky130 goes through magic+netgen and is unaffected, which is why this
only ever showed up on gf180.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Gate the cached venv on a `.installed` marker written after a successful install,
rather than on the python binary existing: a half-built venv used to look like a
cache hit forever. Also stop discarding `uv pip install` output so failures are
visible.
Same defect as the previous commit, second instance. KLayout's SPICE reader
folds a subcircuit's default parameters into its *name*, so

    .subckt DIFF_TO_SINGLE VIN VOUT VSS VSS2 l=1.0 w=6.0 mt=8 mb=10

is read back as the circuit `DIFF_TO_SINGLE(L=1.0,MB=10,MT=8,W=6.0)`. The gf180
klayout deck then cannot match it to the layout's top cell and aborts with
"Can't find a schematic counterpart for the top cell", which the runner reports
as the catch-all "LVS inconclusive (0 mismatches)" -- zero comparisons, not zero
errors.

Unlike two_transistor_interdigitized the device lines here referenced the subckt
parameters as l={l} w={w} m={mt}, so the values are inlined instead. The emitted
netlist is electrically identical; only the parameterisation moves from the
subckt header onto the device lines.

gf180 now produces a real comparison:

    before  LVS inconclusive (0 mismatches)
    after   Netlists do not match (11 mismatches)
            - extra top-level pin(s) in layout: SUB

That remaining mismatch is a genuine discrepancy this change makes visible for
the first time; it is not fixed here. sky130 is unchanged at 5 mismatches
(Magic's PMOS-bulk mis-extraction, the reason this cell is on the default
--skip-cells list). CI is unaffected for the same reason.
…uilds

gf180 has two mutually exclusive MIM stacks. glayout builds option B --
`mimcap` and `mimcap_array` both default to option="B" (primitives/mimcap.py:56,
:333), which is the met4/FuseTop/met5 stack -- but the LVS runner defaulted to
option A (met2/FuseTop/met3).

Extracting A against a B layout yields no capacitor at all, so every MIM in the
cell showed up as missing:

    [FAIL] opamp: Netlists do not match (3 mismatches)
           1 schematic device(s) missing from layout, first 1.2.0.1 [CAP_MIM_2F0FF]

The capacitors were always there: opamp.gds carries FuseTop (75/0) x6 and
MIM_L_MK (117/10) x6 alongside Metal4 and Metal5, six of each matching the six
MIMCap instances in the netlist.

With the default corrected, gf180 LVS is green across every cell, opamp
included. $GF180_MIM_OPTION still overrides for a layout genuinely built on the
met2/met3 stack.

Note the --mim-option flag already existed and was documented, but
.github/workflows/lvs.yml never passed it, so CI has been extracting the wrong
stack for every gf180 cell with a MIM. Fixing the default means the workflow
needs no change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant