feat(precheck): add pin_check for gf180mcuD

and also enable magic drc
This commit is contained in:
htfab
2025-10-29 19:14:45 +02:00
committed by Uri Shaked
parent 0954014041
commit 67541ef759
2 changed files with 54 additions and 46 deletions
+22 -13
View File
@@ -1,6 +1,7 @@
import logging import logging
import re import re
from collections.abc import Iterable from collections.abc import Iterable
from functools import partial
from itertools import combinations from itertools import combinations
from numbers import Real from numbers import Real
@@ -91,7 +92,7 @@ def canonicalize_rectangles(
return sorted(set(closed_rects)) return sorted(set(closed_rects))
def parsefp3(value: str): def parse_fp3(value: str):
# parse fixed-point numbers with 3 digits after the decimal point # parse fixed-point numbers with 3 digits after the decimal point
# e.g. '20.470' to 20470 # e.g. '20.470' to 20470
ip, fp = value.split(".") ip, fp = value.split(".")
@@ -99,6 +100,14 @@ def parsefp3(value: str):
return int(mul) return int(mul)
def parse_dbu_to_nm(value: str, dbu_per_micron: int):
# parse a value in database units into nanometers
assert dbu_per_micron != 0
val_dbu = int(value)
assert (val_dbu * 1000) % dbu_per_micron == 0
return (val_dbu * 1000) // dbu_per_micron
def pin_check( def pin_check(
gds: str, lef: str, template_def: str, toplevel: str, uses_3v3: bool, tech: str gds: str, lef: str, template_def: str, toplevel: str, uses_3v3: bool, tech: str
): ):
@@ -129,18 +138,16 @@ def pin_check(
if line.startswith("UNITS "): if line.startswith("UNITS "):
match = units_re.match(line) match = units_re.match(line)
(dbu_per_micron,) = map(int, match.groups()) (dbu_per_micron,) = map(int, match.groups())
parse_nm = partial(parse_dbu_to_nm, dbu_per_micron=dbu_per_micron)
elif line.startswith("DIEAREA "): elif line.startswith("DIEAREA "):
match = diearea_re.match(line) match = diearea_re.match(line)
lx, by, rx, ty = map(int, match.groups()) lx, by, rx, ty = map(parse_nm, match.groups())
if (lx, by) != (0, 0): if (lx, by) != (0, 0):
raise PrecheckFailure( raise PrecheckFailure(
"Wrong die origin in template DEF, expecting (0, 0)" "Wrong die origin in template DEF, expecting (0, 0)"
) )
assert dbu_per_micron != 0 die_width = rx
assert (rx * 1000) % dbu_per_micron == 0 die_height = ty
assert (ty * 1000) % dbu_per_micron == 0
die_width = (rx * 1000) // dbu_per_micron
die_height = (ty * 1000) // dbu_per_micron
elif line.startswith("PINS "): elif line.startswith("PINS "):
match = pins_re.match(line) match = pins_re.match(line)
pin_count = int(match.group(1)) pin_count = int(match.group(1))
@@ -164,12 +171,12 @@ def pin_check(
line = next(f) line = next(f)
match = layer_re.match(line) match = layer_re.match(line)
layer, lx, by, rx, ty = match.groups() layer, lx, by, rx, ty = match.groups()
lx, by, rx, ty = map(int, (lx, by, rx, ty)) lx, by, rx, ty = map(parse_nm, (lx, by, rx, ty))
line = next(f) line = next(f)
match = placed_re.match(line) match = placed_re.match(line)
ox, oy, direction = match.groups() ox, oy, direction = match.groups()
ox, oy = map(int, (ox, oy)) ox, oy = map(parse_nm, (ox, oy))
if pin_name in def_pins: if pin_name in def_pins:
raise PrecheckFailure("Duplicate pin in template DEF") raise PrecheckFailure("Duplicate pin in template DEF")
@@ -214,14 +221,14 @@ def pin_check(
elif macro_active: elif macro_active:
if line.startswith("ORIGIN "): if line.startswith("ORIGIN "):
match = origin_re.match(line) match = origin_re.match(line)
lx, by = map(parsefp3, match.groups()) lx, by = map(parse_fp3, match.groups())
if lx != 0 or by != 0: if lx != 0 or by != 0:
raise PrecheckFailure( raise PrecheckFailure(
"Wrong die origin in LEF, expecting (0, 0)" "Wrong die origin in LEF, expecting (0, 0)"
) )
elif line.startswith("SIZE "): elif line.startswith("SIZE "):
match = size_re.match(line) match = size_re.match(line)
rx, ty = map(parsefp3, match.groups()) rx, ty = map(parse_fp3, match.groups())
if (rx, ty) != (die_width, die_height): if (rx, ty) != (die_width, die_height):
raise PrecheckFailure( raise PrecheckFailure(
f"Inconsistent die area between LEF and template DEF: ({rx}, {ty}) != ({die_width}, {die_height})" f"Inconsistent die area between LEF and template DEF: ({rx}, {ty}) != ({die_width}, {die_height})"
@@ -250,7 +257,7 @@ def pin_check(
line = next(f).strip() line = next(f).strip()
while line.startswith("RECT "): while line.startswith("RECT "):
match = rect_re.match(line) match = rect_re.match(line)
lx, by, rx, ty = map(parsefp3, match.groups()) lx, by, rx, ty = map(parse_fp3, match.groups())
pin_rects += 1 pin_rects += 1
if current_pin not in lef_ports: if current_pin not in lef_ports:
lef_ports[current_pin] = [] lef_ports[current_pin] = []
@@ -369,6 +376,9 @@ def pin_check(
raise PrecheckFailure("Wrong cell at GDS top-level") raise PrecheckFailure("Wrong cell at GDS top-level")
top = top[0] top = top[0]
gds_errors = 0
if tech != "gf180mcuD":
gds_layers = valid_lef_port_layers[tech] gds_layers = valid_lef_port_layers[tech]
gds_layer_lookup = {j: i for i, j in gds_layers.items()} gds_layer_lookup = {j: i for i, j in gds_layers.items()}
polygon_list = {layer: [] for layer in gds_layers} polygon_list = {layer: [] for layer in gds_layers}
@@ -381,7 +391,6 @@ def pin_check(
for layer in gds_layers: for layer in gds_layers:
merged_layers[layer] = gdstk.boolean(polygon_list[layer], [], "or") merged_layers[layer] = gdstk.boolean(polygon_list[layer], [], "or")
gds_errors = 0
for current_pin, lef_rects in sorted(lef_ports_orig.items()): for current_pin, lef_rects in sorted(lef_ports_orig.items()):
for layer, lx, by, rx, ty in lef_rects: for layer, lx, by, rx, ty in lef_rects:
if layer + ".pin" not in gds_layers: if layer + ".pin" not in gds_layers:
+1 -2
View File
@@ -337,7 +337,7 @@ def main():
{ {
"name": "Magic DRC", "name": "Magic DRC",
"check": lambda: magic_drc(gds_file, top_module), "check": lambda: magic_drc(gds_file, top_module),
"techs": ["sky130A"], "techs": ["sky130A", "gf180mcuD"],
}, },
{ {
"name": "KLayout FEOL", "name": "KLayout FEOL",
@@ -377,7 +377,6 @@ def main():
"check": lambda: pin_check( "check": lambda: pin_check(
gds_file, lef_file, template_def, top_module, uses_3v3, tech gds_file, lef_file, template_def, top_module, uses_3v3, tech
), ),
"techs": ["sky130A", "ihp-sg13g2"],
}, },
{"name": "Boundary check", "check": lambda: boundary_check(gds_file, tech)}, {"name": "Boundary check", "check": lambda: boundary_check(gds_file, tech)},
{ {