feat: add ihp-sg13cmos5l PDK alongside ihp-sg13g2

Based on work done in the ihp-sg13cmos5l branch
This commit is contained in:
Uri Shaked
2026-10-27 11:17:19 +01:00
parent 01d5d2814f
commit 2278ea867e
29 changed files with 5086 additions and 25 deletions
+16 -1
View File
@@ -129,6 +129,14 @@ def klayout_sg13g2(gds: str):
)
def klayout_sg13cmos5l(gds: str):
return klayout_drc(
gds,
"sg13cmos5l",
f"{PDK_ROOT}/{PDK_NAME}/libs.tech/klayout/tech/drc/ihp-sg13cmos5l.drc",
)
def klayout_gf180mcuD_rule_deck(gds: str, top_module: str, check: str, decks: str):
# All gf180mcuD DRC runs go through the PDK's unified rule deck
# (gf180mcu.drc); `decks` selects which rule groups to run (see its
@@ -452,6 +460,8 @@ def main():
pinout = yaml_data.get("pinout", {})
if uses_vapwr and not is_analog:
raise PrecheckFailure("Projects with VAPWR power need at least one analog pin")
if is_analog and tech == "ihp-sg13cmos5l":
raise PrecheckFailure("Analog projects are not supported on ihp-sg13cmos5l yet")
def_root = f"../tech/{tech}/def"
if is_analog:
analog_def = f"{def_root}/analog/tt_analog_{tiles}"
@@ -463,7 +473,7 @@ def main():
template_def = f"{analog_def}_3v3.def"
else:
template_def = f"{analog_def}.def"
elif tech == "ihp-sg13g2" or tech == "gf180mcuD":
elif tech in ("ihp-sg13g2", "ihp-sg13cmos5l", "gf180mcuD"):
template_def = f"{def_root}/tt_block_{tiles}_pgvdd.def"
else:
template_def = f"{def_root}/tt_block_{tiles}_pg.def"
@@ -512,6 +522,11 @@ def main():
"check": lambda: klayout_sg13g2(gds_file),
"techs": ["ihp-sg13g2"],
},
{
"name": "KLayout SG13CMOS5L DRC",
"check": lambda: klayout_sg13cmos5l(gds_file),
"techs": ["ihp-sg13cmos5l"],
},
{"name": "KLayout zero area", "check": lambda: klayout_zero_area(gds_file)},
{
"name": "KLayout Checks",
+1
View File
@@ -5,6 +5,7 @@ drc_pin_label_purposes_overlapping_drawing.xml
drc_zero_area.xml
drc_nwell_urpm.xml
drc_sg13g2.xml
drc_sg13cmos5l.xml
drc_antenna.xml
drc_gf180mcuD.xml
magic_drc.mag
+33 -1
View File
@@ -1,4 +1,4 @@
tech_names = ["sky130A", "ihp-sg13g2", "gf180mcuD"]
tech_names = ["sky130A", "ihp-sg13g2", "ihp-sg13cmos5l", "gf180mcuD"]
# fmt: off
valid_layers_sky130A = [
@@ -78,6 +78,22 @@ valid_layers_ihp_sg13g2 = [
"isoNWell.drawing",
]
# Same as sg13g2, minus layers that don't exist in sg13cmos5l (nBuLay, MIM, Metal5, TopMetal2, ...)
# and minus TopMetal1, which is reserved for the chip-level power grid.
valid_layers_ihp_sg13cmos5l = [
"Substrate.drawing", "Substrate.text", "Activ.drawing", "Activ.label", "Activ.nofill", "Activ.pin", "GatPoly.drawing",
"GatPoly.label", "GatPoly.nofill", "GatPoly.pin", "PolyRes.drawing", "PolyRes.label", "PolyRes.pin", "NWell.drawing",
"NWell.label", "NWell.pin", "PWell.block", "pSD.drawing", "nSD.drawing", "nSD.block", "SalBlock.drawing",
"ThickGateOx.drawing", "Cont.drawing", "Metal1.drawing", "Metal1.label", "Metal1.nofill", "Metal1.pin", "Metal1.slit",
"Metal1.text", "Metal1.res", "Via1.drawing", "Metal2.drawing", "Metal2.label", "Metal2.nofill", "Metal2.pin",
"Metal2.slit", "Metal2.text", "Metal2.res", "Via2.drawing", "Via2.net", "Via2.boundary", "Metal3.drawing",
"Metal3.label", "Metal3.nofill", "Metal3.pin", "Metal3.slit", "Metal3.text", "Metal3.res", "Via3.drawing",
"Metal4.drawing", "Metal4.label", "Metal4.nofill", "Metal4.pin", "Metal4.slit", "Metal4.text", "Metal4.res",
"TopMetal1.nofill", "TEXT.drawing", "Recog.drawing", "Recog.pin", "Recog.esd", "Recog.diode", "Recog.tsv",
"Recog.pdiode", "Recog.mom", "RES.drawing", "RES.label", "SRAM.drawing", "DigiBnd.drawing", "HeatRes.drawing",
"EXTBlock.drawing", "prBoundary.label", "prBoundary.boundary",
]
valid_layers_gf180mcuD = [
'PR_bndry', 'pass_mk', 'fail_mk', 'polygon_mk', 'NAT', 'violation_mk', 'MCELL_FEOL_MK', 'MVPSD', 'rule_txt_mk',
'DNWELL', 'PROBE_MK', 'case_txt_mk', 'Nwell', 'COMP', 'COMP_Dummy', 'COMP_Label', 'ESD', 'ESD_MK', 'Poly2',
@@ -139,11 +155,13 @@ def analog_pin_rects(tech: str, uses_vapwr: bool):
valid_layers = {
"sky130A": valid_layers_sky130A,
"ihp-sg13g2": valid_layers_ihp_sg13g2,
"ihp-sg13cmos5l": valid_layers_ihp_sg13cmos5l,
"gf180mcuD": valid_layers_gf180mcuD,
}
lyp_filename = {
"sky130A": "sky130A.lyp",
"ihp-sg13g2": "sg13g2.lyp",
"ihp-sg13cmos5l": "sg13cmos5l.lyp",
"gf180mcuD": "gf180mcu.lyp",
}
@@ -163,6 +181,12 @@ valid_lef_port_layers = {
"Metal5.pin": (67, 2),
"TopMetal1.pin": (126, 2),
},
"ihp-sg13cmos5l": {
"Metal1.pin": (8, 2),
"Metal2.pin": (10, 2),
"Metal3.pin": (30, 2),
"Metal4.pin": (50, 2),
},
"gf180mcuD": {
"Metal1_label": (34, 10),
"Metal2_label": (36, 10),
@@ -181,6 +205,11 @@ forbidden_layers = {
"TopMetal2.pin",
"TopMetal2.label",
],
"ihp-sg13cmos5l": [
"TopMetal1.drawing",
"TopMetal1.pin",
"TopMetal1.label",
],
"gf180mcuD": [
"Metal5",
"Metal5_Label",
@@ -189,15 +218,18 @@ forbidden_layers = {
power_pins_layer = {
"sky130A": "met4",
"ihp-sg13g2": "TopMetal1",
"ihp-sg13cmos5l": "Metal4",
"gf180mcuD": "Metal4",
}
power_pins_min_width = {
"sky130A": 1200, # 1.2 um
"ihp-sg13g2": 2100, # 2.1 um
"ihp-sg13cmos5l": 2100, # 2.1 um
"gf180mcuD": 800, # 0.8 um
}
boundary_layer = {
"sky130A": "prBoundary.boundary",
"ihp-sg13g2": "prBoundary.boundary",
"ihp-sg13cmos5l": "prBoundary.boundary",
"gf180mcuD": "PR_bndry",
}