ordec.layout.klayout — KLayout integration (DRC/LVS)

This module integrates the external KLayout tool for DRC and LVS. It runs KLayout in batch mode (run()) and parses its result files back into ORDB subgraphs: XML result databases (RDB) into DrcReport (parse_rdb()), and LVS databases (LVSDB) into LvsReport (parse_lvsdb()). PDK-specific entry points such as ordec.lib.ihp130.run_drc and ordec.lib.ihp130.run_lvs build on these functions.

For LVS, ORDeC supplies KLayout with two inputs that are generated from the same Cell hierarchy: a SPICE netlist of the schematic (via Netlister) and a GDS file of the layout (via write_gds), both named through one shared Directory (see Cell name matching below).

Hierarchical LVS and KLayout’s align

KLayout’s netlist comparer works hierarchically: it pairs up circuits (layout cells extracted from the GDS vs. .subckt definitions from the schematic netlist) and compares each pair in isolation, treating instances of already-paired subcircuits as opaque building blocks. Circuits are paired by name (case-insensitively). Each compared pair appears as one LvsCircuitPair in the parsed LvsReport.

This pairing only works when both sides have the same hierarchy. To handle differing hierarchies, the LVS deck invokes KLayout’s align step before the comparison. align finds all circuits that have no same-named counterpart on the other side and flattens them, i.e. inlines their contents into their parent circuits. (The top cell of the layout is excepted: if it has no schematic counterpart, align raises an error instead.)

For hierarchical LVS, this has the following consequences:

  • Cells that exist on both sides (same name) are compared pair by pair, keeping the comparison hierarchical and the report structured.

  • Cells that exist on one side only are flattened away. This covers leaf device cells (e.g. resistor or MOSFET layout cells, whose devices appear directly inside the parent .subckt on the schematic side), but also deliberately different hierarchy cuts: a flat layout can be compared against a hierarchical schematic and vice versa, and even two hierarchies with shifted cell boundaries compare clean as long as they are electrically equivalent after flattening.

  • Objects of flattened circuits appear in the report under dotted hierarchical names (e.g. device B1.A1.R1 = resistor r1 inside instance a1 inside instance b1).

  • Flattening can make structurally identical subcircuits (e.g. two parallel instances of the same cell) topologically symmetric; KLayout then matches the affected nets in an arbitrary but valid way and flags them as ambiguous matches, which parse_lvsdb() represents as LvsStatus.MatchWarning (not as a mismatch).

tests/lib/lvs_example_hier.ord together with tests/test_ihp130_lvs_hier.py exercises all of these cases.

Cell name matching

Because align and the circuit pairing operate purely on names, LVS is only correct if the netlist and GDS names agree exactly: the schematic and layout of one cell must be paired, and views of different cells must never be. ORDeC’s Directory guarantees this name matching in both directions — two circuits are name-matched by KLayout if and only if they belong to the same cell:

  • Same cell ⇒ same name. A Cell subclass with a given (normalized) parameter set is a singleton, and run_lvs uses a single Directory for both netlisting and GDS writing. Directory.name_subgraph() names a subgraph after its cell, memoized per cell object, so the .subckt for A().symbol and the GDS cell for A().layout receive the identical string. As a guard, registering a second, different subgraph of the same kind under one cell raises an error.

  • Different cells ⇒ different names. All top-level names live in one namespace per Directory; name collisions (e.g. equal class names from different modules) are resolved by appending number suffixes, so two distinct cells can never receive the same string. Since Directory names contain only a-z, 0-9 and _, they are also distinct under KLayout’s case-insensitive name normalization.

Note that both directions hold within one Directory, i.e. within one run_lvs invocation — which is sufficient for the name-based pairing, since KLayout sees exactly the netlist and GDS produced by that one directory. Collision suffixes depend on naming order, so names are not guaranteed to be stable across separate runs.

Functions

ordec.layout.klayout.run(script, cwd, **kwargs)

Run KLayout script ‘script’ in directory ‘cwd’ with provided keyword args.

ordec.layout.klayout.parse_rdb(filename, report: DrcReport, directory: Directory = None)

Parse a KLayout XML result database file (RDB), appending the parsed violations into the given DrcReport subgraph.

Parameters:
  • filename – Path to the .lyrdb file.

  • report – Existing DrcReport to append parsed violations into. The checked Layout is taken from report.ref_layout.

  • directory – Optional Directory for looking up cell names to LayoutInstances. If not provided, DrcItem.cell will be None.

RDB format documentation: https://www.klayout.de/rdb_format.html

ordec.layout.klayout.parse_rdb_value(value_str: str)

Parse an RDB <value> string into a (tag, kind, payload) tuple.

The grammar covers the full value space accepted by KLayout’s own reader; see RdbValueTransformer for the payload shape of each kind. Raises LarkError if the string is not a valid RDB value.

ordec.layout.klayout.parse_lvsdb(filename, layout: Layout, schematic: Schematic, directory=None) LvsReport

Parse a KLayout LVS database file (.lvsdb) into an LvsReport subgraph.

Parameters:
  • filename – Path to the .lvsdb file.

  • layout – The Layout subgraph that was checked. Becomes ref_layout of the report and of the top-level LvsCircuitPair. May be None.

  • schematic – The Schematic subgraph that was compared against. Becomes ref_schematic analogously. May be None.

  • directory – Optional Directory used during netlisting and GDS export. If given, it is used to resolve subcircuit pairs to their Layout/Schematic subgraphs and item names to ORDB nodes; without it, only the raw LVSDB names are reported.

Returns:

LvsReport subgraph with all parsed comparison results.

LVSDB format. The format is only documented in the KLayout sources, of which this repository keeps a copy:

  • experiments/klayout/src/db/db/dbLayoutVsSchematicFormatDefs.h defines the LVSDB top level,

  • experiments/klayout/src/db/db/dbLayoutToNetlistFormatDefs.h defines the embedded netlist sections (shared with L2N databases).

An LVSDB file is a tree of parenthesized s-expressions. Every element type has a long and a short key (e.g. circuit and X); KLayout writes short keys, this parser accepts both. After the magic line #%lvsdb-klayout, the file has three top-level sections:

J(...)   layout:    netlist extracted from the GDS
H(...)   reference: netlist read from the SPICE file
Z(...)   xref:      comparison results (pairing + status)

Keys relevant to this parser (long form in parentheses):

Key

Meaning

W

(top) top cell name, in the layout/reference sections

U

(unit) database unit in µm

X

(circuit) circuit; inside a circuit, X with a numeric first element is a subcircuit instance

N

(net) net definition: id, then optional I and geometry

P

(pin) pin definition: id, then optional I

D

(device) device: id, device class, then I/E/Y

I

(name) name of the enclosing net/device/pin/subcircuit

E

(param) device parameter, e.g. E(l 0.5)

Y

(location) device/instance location in database units

L

in the xref section: (log) message log of a circuit pair; in the netlist sections: (layer) layer definition!

M

(entry) one log message inside L(...)

B

(description) message text inside M(...)

Pitfalls:

  • Short keys are context-dependent: H is the reference section at the top level but a message inside netlist sections, J is the layout section at the top level but a text label in net geometry, X may be a circuit, a subcircuit instance or the nomatch status, and L is a log in the xref section but a layer in the netlist sections.

  • Absent values (unpaired ids, missing names) are written as ().

  • In xref items, pin ids are 0-based, while pin definitions in the netlist sections use 1-based ids.

  • In the layout section, devices and subcircuit instances are usually unnamed (GDS structure references carry no instance names) and only identified by their location (Y). In the reference section, names come from the SPICE netlist and are upper-cased.

Status codes (used for circuit pairs and xref items alike):

Code

Long form

Meaning

1

match

objects were paired and compare clean

0

mismatch

objects were paired, but their comparison failed

X

nomatch

no counterpart found on the other side

W

warning

matched with warning: for devices, parameters deviate (an LVS error); for nets, pins and subcircuits, the match was ambiguous (harmless)

S

skipped

comparison skipped

Annotated example (shortened, from a hierarchical resistor design):

#%lvsdb-klayout
J(                        # layout netlist (extracted from GDS)
 W(c_hier)                # top cell
 U(0.001)                 # database unit in µm
 L(l6 '6/0')              # layer definition ("L" = layer here!)
 X(a_default              # circuit = extracted cell "a_default"
  N(1 I(x)                # net 1, named "x", with geometry:
   R(l6 (70 3620) (360 160))  # rect on layer l6
   J(l26 x (-180 -80))        # text label ("J" = text here!)
  )
  P(1 I(x))               # pin 1, named "x"
  D(1 D$rsil$1            # device 1 of device class "D$rsil$1",
   Y(-5 2995)             # unnamed, at location (-5, 2995)
   E(w 0.5) E(l 0.5)      # device parameters
   T(rsil_1 5)            # terminal "rsil_1" connects to net 5
  )
  X(1 a_default Y(0 0)    # subcircuit instance 1 of "a_default"
   P(0 4)                 # instance pin 0 connects to net 4
  )
 )
)
H(                        # reference netlist (from SPICE)
 X(A_DEFAULT              # names are upper-cased SPICE names
  N(1 I(X))
  D(1 RSIL I(R1) ...)     # devices/subcircuits are named here
  X(1 A_DEFAULT I(A1) ...)
 )
)
Z(                        # comparison results
 X(a_default A_DEFAULT 1  # circuit pair: layout circuit,
  Z(                      # reference circuit, status
   N(5 5 1)               # item xref: layout id, reference id,
   P(0 0 1)               # status (pin ids 0-based here!)
   D(3 1 1)
   X(1 1 1)
  )
 )
)

A real specimen of this format is kept at tests/lvsdb/c_hier.lvsdb; tests/test_parse_lvsdb.py parses it to pin down this parser’s behavior independently of KLayout.