feat(precheck): add analog pin check for ihp-sg13g2

This commit is contained in:
htfab
2026-02-21 07:16:36 +02:00
committed by Uri Shaked
parent cff6920d69
commit 45fa89984f
2 changed files with 57 additions and 33 deletions
+28 -21
View File
@@ -17,10 +17,9 @@ from klayout_tools import parse_lyp_layers
from pin_check import pin_check
from precheck_failure import PrecheckFailure
from tech_data import (
analog_pin_pos,
analog_pin_rects,
boundary_layer,
forbidden_layers,
layer_map,
lyp_filename,
tech_names,
valid_layers,
@@ -261,42 +260,50 @@ def analog_pin_check(
if is_analog:
lib = gdstk.read_gds(gds)
top = lib.top_level()[0]
met4 = top.copy("test_met4")
met4.flatten()
met4.filter([layer_map[tech]["met4"]], False)
via3 = top.copy("test_via3")
via3.flatten()
via3.filter([layer_map[tech]["via3"]], False)
filtered = {}
for pin in range(8):
x = analog_pin_pos[tech](pin, uses_3v3)
pin_over = gdstk.rectangle((x, 0), (x + 0.9, 1.0))
pin_around = gdstk.boolean(
gdstk.offset(pin_over, 0.5), gdstk.offset(pin_over, 0.1), "not"
for pin, (rect, pin_layer, via_layers) in enumerate(
analog_pin_rects(tech, uses_3v3)
):
for layer in [pin_layer] + via_layers:
if layer not in filtered:
i = len(filtered)
lf = top.copy(f"test_lf_{i}")
lf.flatten()
lf.filter([layer], False)
filtered[layer] = lf
pin_rect = gdstk.rectangle(*rect)
pin_ring = gdstk.boolean(
gdstk.offset(pin_rect, 0.5), gdstk.offset(pin_rect, 0.1), "not"
)
via3_over = gdstk.boolean(via3.polygons, pin_over, "and")
met4_around = gdstk.boolean(met4.polygons, pin_around, "and")
connected = bool(via3_over) or bool(met4_around)
pin_layer_polygons = filtered[pin_layer].polygons
connected = bool(gdstk.boolean(pin_layer_polygons, pin_ring, "and"))
for via_layer in via_layers:
via_layer_polygons = filtered[via_layer].polygons
connected = connected or bool(
gdstk.boolean(via_layer_polygons, pin_rect, "and")
)
expected_pc = pin < analog_pins
expected_pd = bool(pinout.get(f"ua[{pin}]", ""))
if connected and not expected_pc:
raise PrecheckFailure(
f"Analog pin `ua[{pin}]` is connected to some metal but `analog_pins` is set to {analog_pins} in `info.yaml`. Either increase `analog_pins` to at least {pin+1}, or remove any metal4 or via3 adjacent to `ua[{pin}]`."
f"Analog pin `ua[{pin}]` is connected to some metal but `analog_pins` is set to {analog_pins} in `info.yaml`. Either increase `analog_pins` to at least {pin+1}, or remove any metal or via adjacent to `ua[{pin}]`."
)
elif connected and not expected_pd:
raise PrecheckFailure(
f"Analog pin `ua[{pin}]` is connected to some metal but the description of `ua[{pin}]` in the pinout section of `info.yaml` is empty. Either add a description or remove any metal4 or via3 adjacent to `ua[{pin}]`."
f"Analog pin `ua[{pin}]` is connected to some metal but the description of `ua[{pin}]` in the pinout section of `info.yaml` is empty. Either add a description or remove any metal or via adjacent to `ua[{pin}]`."
)
elif not connected and expected_pc:
raise PrecheckFailure(
f"Analog pin `ua[{pin}]` is not connected to any adjacent metal but `analog_pins` is set to {analog_pins} in `info.yaml`. Either wire up `ua[{pin}]` to your design using metal4 or via3, or decrease `analog_pins` to {pin}."
f"Analog pin `ua[{pin}]` is not connected to any adjacent metal but `analog_pins` is set to {analog_pins} in `info.yaml`. Either wire up `ua[{pin}]` to your design or decrease `analog_pins` to {pin}."
)
elif not connected and expected_pd:
raise PrecheckFailure(
f"Analog pin `ua[{pin}]` is not connected to any adjacent metal but the description of `ua[{pin}]` in the pinout section of `info.yaml` is non-empty. Either wire up `ua[{pin}]` to your design using metal4 or via3, or remove the description for the disconnected pin."
f"Analog pin `ua[{pin}]` is not connected to any adjacent metal but the description of `ua[{pin}]` in the pinout section of `info.yaml` is non-empty. Either wire up `ua[{pin}]` to your design or remove the description for the disconnected pin."
)
@@ -437,7 +444,7 @@ def main():
"check": lambda: analog_pin_check(
gds_file, tech, is_analog, uses_3v3, analog_pins, pinout
),
"techs": ["sky130A"],
"techs": ["sky130A", "ihp-sg13g2"],
},
]
+29 -12
View File
@@ -1,3 +1,5 @@
tech_names = ["sky130A", "ihp-sg13g2", "gf180mcuD"]
# fmt: off
valid_layers_sky130A = [
'cldntm.mask', 'ldntm.drawing', 'cncm.mask', 'ctunm.mask', 'cnwm.mask', 'cnsm.mask', 'cfom.drawing', 'cfom.maskAdd',
@@ -93,15 +95,34 @@ valid_layers_gf180mcuD = [
]
# fmt: on
# layers used for the analog pin check
layer_map_sky130A = {
"met4": (71, 20),
"via3": (70, 44),
}
def analog_pin_pos_sky130A(pin_number: int, uses_3v3: bool):
return 151.81 - 19.32 * pin_number - (15.64 if uses_3v3 else 0)
def analog_pin_rects(tech: str, uses_3v3: bool):
if tech == "sky130A":
pin_layer = (71, 20) # met4
via_layers = [(70, 44)] # via3
for pin_number in range(8):
if uses_3v3:
x1, y1 = 136.17 - 19.32 * pin_number, 0.0
else:
x1, y1 = 151.81 - 19.32 * pin_number, 0.0
x2, y2 = x1 + 0.9, y1 + 1.0
rect = ((x1, y1), (x2, y2))
yield (rect, pin_layer, via_layers)
elif tech == "ihp-sg13g2":
pin_layer = (126, 0) # TopMetal1
via_layers = [(125, 0)] # TopVia1
for pin_number in range(8):
if uses_3v3:
raise NotImplementedError
else:
x1, y1 = 190.165 - 24.48 * pin_number, 0.0
x2, y2 = x1 + 1.75, y1 + 2.0
rect = ((x1, y1), (x2, y2))
yield (rect, pin_layer, via_layers)
elif tech in tech_names:
raise NotImplementedError
else:
raise ValueError(f"unexpected tech {tech}")
valid_layers = {
@@ -109,8 +130,6 @@ valid_layers = {
"ihp-sg13g2": valid_layers_ihp_sg13g2,
"gf180mcuD": valid_layers_gf180mcuD,
}
layer_map = {"sky130A": layer_map_sky130A}
analog_pin_pos = {"sky130A": analog_pin_pos_sky130A}
lyp_filename = {
"sky130A": "sky130A.lyp",
"ihp-sg13g2": "sg13g2.lyp",
@@ -165,5 +184,3 @@ boundary_layer = {
"ihp-sg13g2": "prBoundary.boundary",
"gf180mcuD": "PR_bndry",
}
tech_names = ["sky130A", "ihp-sg13g2", "gf180mcuD"]