Layout Knowledge Base

Verification · Getting started

LVS: layout versus schematic, and how to read the report

Schematic and layout describe one circuit in two languages. How LVS extracts nets from polygons, a LayoutEditor script that checks a layout against a SPICE netlist and against a schematic, and how to read opens, shorts, and device mismatches.

Last edited: October 19, 2026

LayoutEditor: above, a schematic of two resistors R1 and R2 in series with nets IN, MID and OUT; below, the layout of the same circuit as two resistor cells with metal pads and three labeled metal straps

A schematic and a layout describe the same circuit in two languages. The schematic is connectivity: symbols, pins, and named nets. The layout is space: polygons on layers that a fab turns into films. Neither contains the other's specialty. The schematic says nothing about which side of a block a device sits on, and the layout carries no net names unless someone adds text labels. Layout versus schematic (LVS) is the check that proves the two still describe one circuit.

The picture at the top of this page shows both languages for one circuit: two resistors in series, with the nets IN, MID and OUT. The upper half is the schematic, drawn in LayoutEditor's schematic editor. The lower half is the layout, drawn in LayoutEditor too: two resistor cells, each with a metal pad on both ends and a body in between, and three metal straps that carry the net names. Every claim on the schematic has to be found again in the metal, and this page runs that check with real commands and shows what it prints.

Two netlists, one comparison

LVS does three things.

  1. Extract devices. The extractor has to know what the devices are. In a production deck, Boolean operations on the drawing layers find device bodies: active inside the n-well and under p+ implant, crossed by poly, is a PMOS gate, and the active left over on either side is source and drain. In the example below, a device is simply a named cell reference.
  2. Extract connectivity. Shapes on the same layer that touch or overlap become one net. Shapes on different layers connect only where a cut layer, a contact or a via, overlaps both. The result is a netlist taken from geometry.
  3. Compare. The extracted netlist is matched against the reference netlist written from the schematic, usually SPICE. Same devices, same device parameters within tolerance, same pins tied together, nothing extra, nothing missing.

LVS does not grade the circuit design. It grades whether you built the circuit you wrote down. It is also not a geometry check: DRC can pass a cell that is missing a contact, because every shape that is there is wide enough and far enough from its neighbors. LVS fails it.

Devices here are named cell references

To keep every step visible, the example uses the simplest kind of device: a cell you place. The resistor is one cell, RES, with a metal pad at each end, a body between the pads that is not metal, and the pad labels A and B. R1 and R2 are two instances of that cell (see cells and instances). LVS needs to know which reference is which device, so each reference carries its name as a GDS property (number 10). Nothing is recognized from diffusion or poly in this example, and no transistor is extracted. The device is whatever the cell reference says it is, and the extractor takes its pins from the labels on the cell.

The net names come from text labels on the metal straps: IN, MID and OUT. A label names the net of the shape it sits on (see nets, pins and labels). The layout script is short enough to read in one piece:

def build_layout(mid_um=4, name_devices=True):
    layout = project.newLayout(); d = layout.drawing
    res = d.currentCell; res.cellName = "RES"                       # the device: one cell, two pads
    res.addBox(0, 0, 2*um, 6*um, M1); res.addBox(8*um, 0, 2*um, 6*um, M1)
    res.addBox(2*um, 3*um//2, 6*um, 3*um, BODY)                     # body, not a conductor
    res.addText(M1, point(1*um, 3*um), "A")                         # pin labels
    res.addText(M1, point(9*um, 3*um), "B")
    d.newCell(); top = d.currentCell; top.cellName = "TOP"
    r1 = top.addCellref(res, point(0, 0)); r2 = top.addCellref(res, point(14*um, 0))
    if name_devices:
        r1.setPropertyString(10, "R1"); r2.setPropertyString(10, "R2")   # property 10 = device name
    top.addBox(-4*um, 2*um, 4*um, 2*um, M1)                         # IN strap
    top.addBox(10*um, 2*um, mid_um*um, 2*um, M1)                    # MID strap, 4 um joins R1 and R2
    top.addBox(24*um, 2*um, 4*um, 2*um, M1)                         # OUT strap
    top.addText(M1, point(-3*um, 3*um), "IN"); top.addText(M1, point(11*um, 3*um), "MID")
    top.addText(M1, point(26*um, 3*um), "OUT")                      # net labels
    return layout

The picture at the top of this page shows this layout under a schematic of the same circuit. The slate rectangles are metal, the tan rectangles are the resistor bodies, which are drawn on their own layer and conduct nothing. Both resistors reach the middle strap through their B pad and their A pad, so MID is one net with two pins on it.

Comparing against a netlist

The reference is a SPICE file. It describes the cell RES with its two pins and the cell TOP with its three nets, in the same names the layout uses:

* two resistor cells in series
.subckt RES A B
.ends RES
.subckt TOP IN MID OUT
XR1 IN MID RES
XR2 MID OUT RES
.ends TOP

The comparison has four calls: declare which layer conducts, build the connection, extract the netlist from the layout, and compare it with the loaded file:

def compare_netlist(layout, netlist_file):
    nt = layout.netlistTool
    nt.technologyLayerRemoveAll(); nt.technologyLayerAdd(M1, 2)     # layer 1 conducts
    nt.buildConnect(); nt.extractNetList()                          # what touches, then the netlist
    nt.netlistLoad(netlist_file)                                    # SPICE, .subckt named like the cell
    nt.layoutVersusNetlist()
    r = nt.getLVSResults()
    return [r.at(i) for i in range(r.size())]

technologyLayerAdd(1, 2) says that layer 1 is a conductor (2 means conductor, 1 would mean via). buildConnect() finds which shapes touch, and extractNetList() turns the result into a netlist. netlistLoad() reads the SPICE file, whose TOP subcircuit must be named like the layout's top cell. layoutVersusNetlist() runs the comparison and getLVSResults() returns its findings as text lines. Run on the layout above, with the good netlist:

python3 lvs_two_resistors.py rr_good.sp
No errors.

One line, and it is the line you want. The script exits normally in every case, so a flow that wants a pass/fail has to look for anything other than "No errors.".

When the comparison fails

A report that has never failed has not been tested, so the test script feeds the same layout three other ways of being wrong. The first is a netlist that wires R2 between IN and OUT instead of between MID and OUT (XR2 IN OUT RES in place of XR2 MID OUT RES):

misconnection R2/A

The second is a netlist with a third resistor the layout never drew (XR3 OUT IN RES added):

missing device R3

The word "missing" is relative to the layout: the netlist has a device that the layout lacks. The third is a defect in the layout instead of the netlist. The MID strap is drawn 2 µm long instead of 4 µm, so it no longer reaches R2. This is the case shown in the second picture.

Two resistor cells side by side in LayoutEditor: the MID strap on the left cell stops 2 µm short of the pad of the right cell, leaving a gap in the metal

The gap is 2 µm wide and easy to miss at normal zoom, but LVS finds it at once and names the pin that lost its net:

connection missing R2/A

A stray strip of metal laid across R1, from its A pad to its B pad, joins IN and MID into one net. The report does not say "short". It lists the pins that lost their nets and a label that has no net left:

connection missing R1/B
connection missing R2/A
external node MID not labeled

The last wrong layout forgets to name the devices. Without property 10 on the references, LVS has two instances and no names to match them against:

different device names R1/
double devicename 
different device names R2/

Lines can come out in any order from run to run, so the test script compares them as sorted lists. The lines themselves name a device and a pin, never a coordinate: the work is to look at that pin in the layout.

Comparing against a schematic

A netlist file is not the only reference. LayoutEditor can also hold a schematic next to the layout and compare against it directly with layoutVersusSchematic(). The schematic is drawn on a sheet named like the layout's top cell, with two resistors from the component library, wires, and three ports named IN, MID and OUT:

def draw_schematic(layout, rewire=False):
    sch = project.getSchematic(layout)                          # schematic window linked to this layout
    sheet = sch.drawing.currentSheet; sheet.sheetName = "TOP"   # same name as the layout's top cell
    res = components.findComponent("R", "PCB")                  # library resistor, pins pin1 and pin2
    for name, x in (("R1", 0), ("R2", 300)):
        sheet.addPlacement(res, point(x, 0), strans()).addParameter("devicename", name)
    wire(sheet, (-30, 0), (-100, 0)); sheet.addPort(point(-100, 0), "IN")
    wire(sheet, (30, 0), (150, 0)); sheet.addPort(point(150, 0), "MID")
    wire(sheet, (330, 0), (400, 0)); sheet.addPort(point(400, 0), "OUT")
    if rewire: wire(sheet, (-30, 0), (-30, -80), (270, -80), (270, 0))   # R2.pin1 to IN
    else: wire(sheet, (150, 0), (270, 0))                                # R2.pin1 to MID
    sch.drawing.updateCurrentNetlist()

The schematic is the picture's upper half. It also generates its own names. A resistor placed with the device name R1 produces a device whose cell name is R10-1206-R1, and the layout cell must carry exactly that name, or LVS reports the schematic's device missing and the layout's device additional. So the layout script asks the schematic for its device list and builds one layout cell for each entry, instead of typing the names by hand. The pins of the library resistor are called pin1 and pin2, so the layout cell is labeled pin1 and pin2:

def build_layout(layout, mid_um=4, name_devices=True):
    d = layout.drawing; nets = layout.netlistTool.getSchematicNetList("TOP")
    cells = []
    for i in range(nets.devicesCount()):
        dev = nets.getDevice(i)                                 # the schematic names every device
        if i: d.newCell()
        cell = d.currentCell; cell.cellName = dev.cellname      # layout cell = schematic's cell name
        cell.addBox(0, 0, 2*um, 6*um, M1); cell.addBox(8*um, 0, 2*um, 6*um, M1)
        cell.addBox(2*um, 3*um//2, 6*um, 3*um, BODY)
        cell.addText(M1, point(1*um, 3*um), "pin1"); cell.addText(M1, point(9*um, 3*um), "pin2")
        cells.append((cell, dev.devicename))
    d.newCell(); top = d.currentCell; top.cellName = "TOP"
    for cell, name in cells:
        ref = top.addCellref(cell, point(14*um*(int(name[1:]) - 1), 0))
        if name_devices:
            ref.setPropertyString(10, name)                     # property 10 = device name
    top.addBox(-4*um, 2*um, 4*um, 2*um, M1); top.addBox(10*um, 2*um, mid_um*um, 2*um, M1)
    top.addBox(24*um, 2*um, 4*um, 2*um, M1)
    top.addText(M1, point(-3*um, 3*um), "IN"); top.addText(M1, point(11*um, 3*um), "MID")
    top.addText(M1, point(26*um, 3*um), "OUT")
    return cells

The comparison itself needs no netlist file, because the schematic is the reference:

def compare_schematic(layout):
    nt = layout.netlistTool
    nt.technologyLayerRemoveAll(); nt.technologyLayerAdd(M1, 2)  # layer 1 conducts
    nt.buildConnect(); nt.extractNetList()
    nt.layoutVersusSchematic()
    r = nt.getLVSResults()
    return [r.at(i) for i in range(r.size())]

With a matching schematic it prints No errors. just like the netlist flow. The test script then breaks each side once: it rewires R2's first pin to IN in the schematic, shortens the MID strap in the layout, adds a third resistor to the schematic after the layout was drawn, strips the device names from the references, and gives the layout cells names of its own instead of the schematic's. The reports are:

Change Report
Schematic wires R2.pin1 to IN misconnection R2/pin1
Layout MID strap too short connection missing R2/pin1
Schematic has an extra R3 missing device R3
References without device names different device names R1/, double devicename, different device names R2/
Layout cells named RES_R1, RES_R2 missing device R1, missing device R2, additional device R1, additional device R2

The vocabulary is the same as for the netlist file. The last row is the one to remember: a name that differs by a prefix looks like two devices missing and two added.

LayoutEditor's documentation also describes recognizing devices from layers, where MOS transistors, resistors, capacitors and bipolar devices are found from their drawing layers. This page does not use it, and it does not claim a result for it.

A gap is a missing contact

The second picture above is the simplest open: metal that stops short of a pad. The same thing happens in a real device stack when a contact or via is missing. Metal still runs along the device, and at a glance the device looks connected. It is not. Metal that never meets a contact on the active is a shape beside the device, not a pin of it. On the schematic, that end is tied to a named net; in the extracted netlist, the pin has no net. The report shows a connection missing.

The mistake is easy to miss because the contact is the small square and the bar is the shape the eye follows. A contact around 0.17 µm on a side under a metal strap several micrometers wide is the overlap an extractor uses. A contact drawn on the wrong layer number is as missing as one never placed, even if the color map paints it like a contact.

Touches, gaps, and crossings

The two classic failures are mirror images. Picture two devices on one metal path. If the left joint overlaps the device metal and the right joint stops a fraction of a micrometer short, that gap is an open: invisible at normal zoom, but the extractor sees two nets where the schematic has one. Now picture a second path on another metal layer routed up and over the first without landing on a via. It stays a separate net, which is correct. If it dipped onto the first path's layer and touched it, two schematic nets would merge into one: a short.

Rows of devices do not inherit nets from sitting side by side. They connect because shapes touch on one layer, or because a cut joins two layers. Anything else is a picture of a connection.

Reading an LVS report

A mismatch report names devices and pins, not coordinates, so work from names. These are the lines the tests above produced:

  • Open. One schematic net appears as two or more extracted nets, so a pin lost its net: connection missing R2/A. Look for missing contacts or vias, gaps, or a label placed on the wrong shape.
  • Wrong net. A pin sits on a net the reference does not give it: misconnection R2/A. Compare what the pin touches with where the schematic wires it.
  • Short. Two schematic nets appear as one extracted net. In the bridge test the report lists pins that lost their nets and a label without a net: connection missing R1/B, connection missing R2/A, external node MID not labeled. A short between two labeled supplies (VDD and VSS) can make the whole cell fail at once.
  • Device mismatch. A device exists on only one side: missing device R3 when the reference has it and the layout does not, additional device R1 when the layout has one the reference does not know. A pair of missing and additional lines with nearly equal names usually means a naming difference, as in the RES_R1 test.
  • Names. different device names and double devicename mean the references carry no names or the same name twice. Pin names come from labels, so a misspelled label shows up as a pin or net mismatch.

Fix the document that is actually wrong. If the schematic changed and the layout did not follow, the layout is wrong; if a designer patched the layout to make it fit and never updated the sheet, the schematic is. Never rename nets just to silence the report. Rerun LVS after every change, including fixes for DRC errors, because widening a wire to fix a spacing violation can create a short.

Where LVS sits in the flow

DRC answers whether every shape can be built. LVS answers whether the shapes form the intended circuit. A signoff run needs both clean, plus antenna and density checks. Parasitic extraction, which adds wire resistance and capacitance for timing and analog simulation, builds on the same extracted netlist and is only meaningful after LVS passes. The schematic and the layout stay cousins only as long as the comparison runs: every time one changes, LVS is what keeps them speaking the same language.

Production kits ship their decks ready-made. The open SKY130 flow commonly runs extraction in the Magic layout tool and the comparison in netgen; KLayout has an LVS engine of its own with decks for open PDKs. You rarely write the device recognition yourself, but you should be able to read the report when it surprises you.

Continue exploring