Skip to content

Electrical Short (Through Via)

File: pics/via_short.pic.yml

Error caught: short — a VIA at the crossing of an M1 route and an M2 route bridges two independent nets, creating a cross-layer short.

Error type: LVS.short

Expected: ok=False, error_count=2 (1 cross-layer short + 1 missing_in_schematic net group derived from the short)

import tempfile
from copy import deepcopy
from pathlib import Path

import elvis
import gdsfactory as gf
from IPython.display import Markdown
from kwasm import Tool, show

gf.gpdk.PDK.activate()

PICS = Path("../pics")
BUILD_GDS = Path("../build/gds")
BUILD_GDS.mkdir(parents=True, exist_ok=True)
PIC = PICS / "via_short.pic.yml"

Schematic

The layout shows two crossing routes on different metal layers with a VIA at their intersection. Use the layer panel to toggle M1/M2/VIA1 visibility independently.

schematic = elvis.load_schematics(PIC)
schematic
{'via_short': {'instances': {'pad_m1_a': {'component': 'pad',
    'settings': {'layer': 'M1'}},
   'pad_m1_b': {'component': 'pad', 'settings': {'layer': 'M1'}},
   'pad_m2_a': {'component': 'pad', 'settings': {'layer': 'M2'}},
   'pad_m2_b': {'component': 'pad', 'settings': {'layer': 'M2'}},
   'via': {'component': 'via', 'settings': {'layer': 'VIA1', 'size': [5, 5]}}},
  'routes': {'route_m1': {'links': {'pad_m1_a,e3': 'pad_m1_b,e1'},
    'routing_strategy': 'route_bundle_electrical',
    'settings': {'allow_layer_mismatch': False,
     'allow_type_mismatch': False,
     'allow_width_mismatch': False,
     'cross_section': 'metal1'}},
   'route_m2': {'links': {'pad_m2_a,e4': 'pad_m2_b,e2'},
    'routing_strategy': 'route_bundle_electrical',
    'settings': {'allow_layer_mismatch': False,
     'allow_type_mismatch': False,
     'allow_width_mismatch': False,
     'cross_section': 'metal2'}}},
  'ports': {},
  'placements': {'pad_m1_a': {'x': 0, 'y': 0},
   'pad_m1_b': {'x': 800, 'y': 0},
   'pad_m2_a': {'x': 400, 'y': 400},
   'pad_m2_b': {'x': 400, 'y': -400},
   'via': {'x': 400, 'y': 0.0}}}}

Build from schematic

gds_path = BUILD_GDS / "via_short.gds"
c = gf.read.from_yaml(schematic["via_short"])
c.write_gds(gds_path)
show(
    gds_path,
    netlist=PIC,
    layers=True,
    tools=[Tool.RULER, Tool.CLEAR_ALL, Tool.TOP_PORTS],
)
/home/runner/work/elvis/elvis/.venv/lib/python3.12/site-packages/gdsfactory/read/from_yaml.py:807: UserWarning: No registered width taper for layer M1. Skipping.
  c = _add_routes(c, refs, net.routes, routing_strategies)
/home/runner/work/elvis/elvis/.venv/lib/python3.12/site-packages/gdsfactory/read/from_yaml.py:807: UserWarning: No registered width taper for layer M2. Skipping.
  c = _add_routes(c, refs, net.routes, routing_strategies)
GDS Layout Preview

Tip

Use the layer panel (left sidebar) to toggle M1 and M2 visibility independently — observe that the two routes cross at the VIA position.

LVS Results

rdb = elvis.lvs_rdb(
    gds_path,
    schematic,
    short_layers=[(49, 0)],
    equivalent_ports={"pad": ["pad", "e1", "e2", "e3", "e4"]},
    connected_layers=[((44, 0), (41, 0)), ((44, 0), (45, 0))],
)
lyrdb = Path(tempfile.gettempdir()) / "via_short.lyrdb"
rdb.save(str(lyrdb))
show(
    gds_path,
    lyrdb=lyrdb,
    netlist=PIC,
    layers=True,
    tools=[Tool.SELECT, Tool.RULER, Tool.CLEAR_ALL],
)
GDS Layout Preview

flags used

The above LVS function is called with the following flags

  • short_layers=[(49, 0)]
  • equivalent_ports={'pad': ["pad", "e1", "e2", "e3", "e4"]}
  • connected_layers=[((44, 0), (41, 0)), ((44, 0), (45, 0))]

This can also be pre-configured.

Errors in detail:

print(f"ok={rdb.num_items() == 0}, error_count={rdb.num_items()}")
Markdown(elvis.error_summary(rdb))
ok=False, error_count=2
cell error type description
via_short LVS.net.missing_in_schematic Net {pad_m1_b,{pad,e1,e2,e3,e4}; pad_m2_b,{pad,e1,e2,e3,e4}; pad_m2_a,{pad,e1,e2,e3,e4}; pad_m1_a,{pad,e1,e2,e3,e4}} in layout but not in schematic
via_short LVS.short Geometric short between 'pad_m2_a,e4 -> pad_m2_b,e2' and 'pad_m1_b,e1 -> pad_m1_a,e3' through 'via' (2 locations)

Fix

In this case, the via is probably intentionally placed here because it's perfectly in the middle of the crossing. When such an intentional via causes an LVS error its most likely because the input netlist did not declare the connection the via is making: remember placing something intentionally does not declare its connections. A net needs to be added to the schematic for this declaration:

schematic2 = deepcopy(schematic)
schematic2["via_short"]["nets"] = [
    {"p1": "pad_m1_a,e3", "p2": "pad_m2_a,e4"},
]
c2 = gf.read.from_yaml(schematic2["via_short"])
c2.write_gds(gds_path)
rdb = elvis.lvs_rdb(
    gds_path,
    schematic2,
    short_layers=[(49, 0)],
    equivalent_ports={
        "pad": ["pad", "e1", "e2", "e3", "e4"],
    },
    connected_layers=[
        ((44, 0), (41, 0)),
        ((44, 0), (45, 0)),
    ],
)
rdb.save(str(lyrdb))
show(
    gds_path,
    lyrdb=lyrdb,
    netlist=PIC,
    layers=True,
    tools=[Tool.SELECT, Tool.RULER, Tool.CLEAR_ALL],
)
/home/runner/work/elvis/elvis/.venv/lib/python3.12/site-packages/gdsfactory/read/from_yaml.py:807: UserWarning: No registered width taper for layer M1. Skipping.
  c = _add_routes(c, refs, net.routes, routing_strategies)
/home/runner/work/elvis/elvis/.venv/lib/python3.12/site-packages/gdsfactory/read/from_yaml.py:807: UserWarning: No registered width taper for layer M2. Skipping.
  c = _add_routes(c, refs, net.routes, routing_strategies)
GDS Layout Preview

Why it matters

VIA-induced shorts are among the hardest layout bugs to spot visually — the via is at a crossing point, and each route looks correct on its own layer. The short only becomes apparent when both layers and the via are viewed together. Elvis traces cross-layer connectivity through VIA polygons and flags any net merger that contradicts the schematic, making these invisible bugs findable.