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.
{'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)
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],
)
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)
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.