From 392af85d4fa7f5ce524e14445f4788adc6362e7b Mon Sep 17 00:00:00 2001 From: setup99 Date: Thu, 16 Apr 2026 14:14:18 +0100 Subject: [PATCH] Add IHP, SKY130, and GF180 PDK support and detailed parameter templates --- chipcompiler/data/parameter.py | 243 ++++++++++++++++++++++++++++++++- chipcompiler/data/pdk.py | 173 ++++++++++++++++++++++- 2 files changed, 405 insertions(+), 11 deletions(-) diff --git a/chipcompiler/data/parameter.py b/chipcompiler/data/parameter.py index 45cc8c7..a35b8c7 100644 --- a/chipcompiler/data/parameter.py +++ b/chipcompiler/data/parameter.py @@ -5,6 +5,148 @@ from copy import deepcopy from dataclasses import dataclass, field +# ================= 1. IHP SG13G2 (Explicit) ================= +SG13G2_PARAMETERS_TEMPLATE = { + "PDK": "sg13g2", + "Design": "", "Top module": "", + "Die": {"Size": [], "Area": 0}, + "Core": { + "Size": [], "Area": 0, "Bounding box": "", + "Utilitization": 0.65, "Margin": [17.5, 17.5], "Aspect ratio": 1 + }, + "Max fanout": 20, + "Target density": 0.65, + "Target overflow": 0.1, + "Global right padding": 0, + "Cell padding x": 0, + "Routability opt flag": 1, + "Clock": "clk", + "Frequency max [MHz]": 100, + "Bottom layer": "Metal2", + "Top layer": "Metal5", + "Floorplan": { + "Tap distance": 0, + "Auto place pin": {"layer": "Metal3", "width": 300, "height": 600, "sides": []}, + "Tracks": [ + {"layer": "Metal1", "x start": 0, "x step": 420, "y start": 0, "y step": 420}, + {"layer": "Metal2", "x start": 0, "x step": 480, "y start": 0, "y step": 480}, + {"layer": "Metal3", "x start": 0, "x step": 420, "y start": 0, "y step": 420}, + {"layer": "Metal4", "x start": 0, "x step": 480, "y start": 0, "y step": 480}, + {"layer": "Metal5", "x start": 0, "x step": 420, "y start": 0, "y step": 420}, + ] + }, + "PDN": { + "IO": [ + {"net name": "VDD", "direction": "INOUT", "is power": True}, + {"net name": "VSS", "direction": "INOUT", "is power": False} + ], + "Global connect": [ + {"net name": "VDD", "instance pin name": "VDD", "is power": True}, + {"net name": "VSS", "instance pin name": "VSS", "is power": False} + ], + "Grid": {"layer": "Metal1", "power net": "VDD", "power ground": "VSS", "width": 0.44, "offset": 0}, + "Stripe": [ + {"layer": "Metal4", "power net": "VDD", "ground net": "VSS", "width": 1.6, "pitch": 20, "offset": 1}, + {"layer": "Metal5", "power net": "VDD", "ground net": "VSS", "width": 1.6, "pitch": 20, "offset": 1} + ], + "Connect layers": [{"layers": ["Metal1", "Metal5"]}, {"layers": ["Metal4", "Metal5"]}] + } +} + +# ================= 2. GF180MCU (Explicit) ================= +GF180_PARAMETERS_TEMPLATE = { + "PDK": "gf180mcu", + "Design": "", "Top module": "", + "Die": {"Size": [], "Area": 0}, + "Core": { + "Size": [], "Area": 0, "Bounding box": "", + "Utilitization": 0.50, "Margin": [20, 20], "Aspect ratio": 1 + }, + "Max fanout": 20, + "Target density": 0.45, + "Target overflow": 0.1, + "Global right padding": 0, + "Cell padding x": 0, + "Routability opt flag": 1, + "Clock": "clk", + "Frequency max [MHz]": 100, + "Bottom layer": "Metal1", + "Top layer": "Metal5", + "Floorplan": { + "Tap distance": 0, + "Auto place pin": {"layer": "Metal3", "width": 400, "height": 800, "sides": []}, + "Tracks": [ + {"layer": "Metal1", "x start": 0, "x step": 480, "y start": 0, "y step": 480}, + {"layer": "Metal2", "x start": 0, "x step": 560, "y start": 0, "y step": 560}, + {"layer": "Metal3", "x start": 0, "x step": 480, "y start": 0, "y step": 480}, + {"layer": "Metal4", "x start": 0, "x step": 560, "y start": 0, "y step": 560}, + {"layer": "Metal5", "x start": 0, "x step": 480, "y start": 0, "y step": 480}, + ] + }, + "PDN": { + "IO": [ + {"net name": "VDD", "direction": "INOUT", "is power": True}, + {"net name": "VSS", "direction": "INOUT", "is power": False} + ], + "Global connect": [ + {"net name": "VDD", "instance pin name": "VDD", "is power": True}, + {"net name": "VSS", "instance pin name": "VSS", "is power": False} + ], + "Grid": {"layer": "Metal1", "power net": "VDD", "power ground": "VSS", "width": 0.6, "offset": 0}, + "Stripe": [ + {"layer": "Metal4", "power net": "VDD", "ground net": "VSS", "width": 2.0, "pitch": 25, "offset": 1}, + {"layer": "Metal5", "power net": "VDD", "ground net": "VSS", "width": 2.0, "pitch": 25, "offset": 1} + ], + "Connect layers": [{"layers": ["Metal1", "Metal5"]}, {"layers": ["Metal4", "Metal5"]}] + } +} +# ================= 3. SKY130 (Explicit) ================= +SKY130_PARAMETERS_TEMPLATE = { + "PDK": "sky130", + "Design": "", "Top module": "", + "Die": {"Size": [], "Area": 0}, + "Core": { + "Size": [], "Area": 0, "Bounding box": "", + "Utilitization": 0.40, "Margin": [10, 10], "Aspect ratio": 1 + }, + "Max fanout": 20, + "Target density": 0.40, + "Target overflow": 0.1, + "Global right padding": 0, + "Cell padding x": 0, + "Routability opt flag": 1, + "Clock": "clk", + "Frequency max [MHz]": 100, + "Bottom layer": "met1", + "Top layer": "met5", + "Floorplan": { + "Tap distance": 0, + "Auto place pin": {"layer": "met3", "width": 300, "height": 600, "sides": []}, + "Tracks": [ + {"layer": "met1", "x start": 0, "x step": 340, "y start": 0, "y step": 340}, + {"layer": "met2", "x start": 0, "x step": 460, "y start": 0, "y step": 460}, + {"layer": "met3", "x start": 0, "x step": 340, "y start": 0, "y step": 340}, + {"layer": "met4", "x start": 0, "x step": 460, "y start": 0, "y step": 460}, + {"layer": "met5", "x start": 0, "x step": 340, "y start": 0, "y step": 340}, + ] + }, + "PDN": { + "IO": [ + {"net name": "VPWR", "direction": "INOUT", "is power": True}, + {"net name": "VGND", "direction": "INOUT", "is power": False} + ], + "Global connect": [ + {"net name": "VPWR", "instance pin name": "VPWR", "is power": True}, + {"net name": "VGND", "instance pin name": "VGND", "is power": False} + ], + "Grid": {"layer": "met1", "power net": "VPWR", "power ground": "VGND", "width": 0.48, "offset": 0}, + "Stripe": [ + {"layer": "met4", "power net": "VPWR", "ground net": "VGND", "width": 1.6, "pitch": 20, "offset": 1}, + {"layer": "met5", "power net": "VPWR", "ground net": "VGND", "width": 1.6, "pitch": 20, "offset": 1} + ], + "Connect layers": [{"layers": ["met1", "met5"]}, {"layers": ["met4", "met5"]}] + } +} ICS55_PARAMETERS_TEMPLATE = { "PDK":"ICS55", "Design":"", @@ -33,6 +175,73 @@ "Top layer" : "MET5" } +# ================= 1. IHP SG13G2 Design Parameters ================= +SG13G2_DESIGN_PARAMETERS = { + "gcd": { + "Design": "gcd", + "Top module": "gcd", + "Clock": "clk", + "Frequency max [MHz]": 100, + }, + "aes_cipher_top": { + "Design": "aes", + "Top module": "aes_cipher_top", + "Clock": "clk", + "Frequency max [MHz]": 125, + }, + "picorv32a": { + "Design": "picorv32", + "Top module": "picorv32a", + "Clock": "clk", + "Frequency max [MHz]": 50, + } +} + +# ================= 2. GF180MCU Design Parameters ================= +GF180_DESIGN_PARAMETERS = { + "gcd": { + "Design": "gcd", + "Top module": "gcd", + "Clock": "clk", + "Frequency max [MHz]": 50, + }, + "aes_cipher_top": { + "Design": "aes", + "Top module": "aes_cipher_top", + "Clock": "clk", + "Frequency max [MHz]": 100, + }, + "picorv32a": { + "Design": "picorv32", + "Top module": "picorv32a", + "Clock": "clk", + "Frequency max [MHz]": 33, + } +} + +# ================= 3. SKY130 Design Parameters ================= +SKY130_DESIGN_PARAMETERS = { + "gcd": { + "Design": "gcd", + "Top module": "gcd", + "Clock": "clk", + "Frequency max [MHz]": 100, + }, + "aes_cipher_top": { + "Design": "aes", + "Top module": "aes_cipher_top", + "Clock": "clk", + "Frequency max [MHz]": 100, + }, + "picorv32a": { + "Design": "picorv32", + "Top module": "picorv32a", + "Clock": "clk", + "Frequency max [MHz]": 50, + } +} + + ICS55_DESIGN_PARAMETERS = { "gcd": { "Design": "gcd", @@ -72,9 +281,16 @@ def get_parameters(pdk_name : str = "", path : str = "") -> Parameters: parameters = Parameters() parameters.path = path + # Using the match statement as requested match pdk_name.lower(): case "ics55": parameters.data = deepcopy(ICS55_PARAMETERS_TEMPLATE) + case "sg13g2" | "ihp130": + parameters.data = deepcopy(SG13G2_PARAMETERS_TEMPLATE) + case "gf180mcu" | "gf180": + parameters.data = deepcopy(GF180_PARAMETERS_TEMPLATE) + case "sky130": + parameters.data = deepcopy(SKY130_PARAMETERS_TEMPLATE) return parameters @@ -83,14 +299,31 @@ def get_design_parameters(pdk_name : str, design : str = "", path : str = "") -> Return parameters resolved by PDK and optional design name. """ parameters = get_parameters(pdk_name, path) - if not design or pdk_name.lower() != "ics55": + if not design: return parameters - design_info = ICS55_DESIGN_PARAMETERS.get(design.lower()) - if design_info is None: - return parameters + pdk_low = pdk_name.lower() + design_low = design.lower() + design_info = None + + # Match the PDK to its specific design parameter dictionary + match pdk_low: + case "ics55": + design_info = ICS55_DESIGN_PARAMETERS.get(design_low) + case "sg13g2" | "ihp130": + # Assuming you created SG13G2_DESIGN_PARAMETERS dictionary + design_info = SG13G2_DESIGN_PARAMETERS.get(design_low) + case "gf180mcu" | "gf180": + # Assuming you created GF180_DESIGN_PARAMETERS dictionary + design_info = GF180_DESIGN_PARAMETERS.get(design_low) + case "sky130": + # Assuming you created SKY130_DESIGN_PARAMETERS dictionary + design_info = SKY130_DESIGN_PARAMETERS.get(design_low) + + # If design info was found for that specific PDK, update the parameters + if design_info is not None: + parameters.data.update(design_info) - parameters.data.update(design_info) return parameters def update_parameters(parameters_src : dict, parameters_target : dict) -> dict: diff --git a/chipcompiler/data/pdk.py b/chipcompiler/data/pdk.py index ef1744d..403f966 100644 --- a/chipcompiler/data/pdk.py +++ b/chipcompiler/data/pdk.py @@ -48,17 +48,20 @@ def validate(self) -> None: msg = "PDK validation failed:\n " + "\n ".join(errors) logger.error(msg) raise ValueError(msg) - + def get_pdk(pdk_name : str, pdk_root: str = "") -> PDK: - """ - Return the PDK instance based on the given pdk name. - """ pdk_name_normalized = (pdk_name or "").strip().lower() if pdk_name_normalized == "ics55": pdk = PDK_ICS55(pdk_root=pdk_root) + elif pdk_name_normalized == "sg13g2": + pdk = PDK_SG13G2(pdk_root=pdk_root) + elif pdk_name_normalized == "gf180mcu": + pdk = PDK_GF180MCU(pdk_root=pdk_root) + elif pdk_name_normalized in ["sky130", "skywater130"]: + pdk = PDK_SKY130(pdk_root=pdk_root) else: pdk = PDK(name=pdk_name_normalized) - pdk.validate() + return pdk def PDK_ICS55(pdk_root: str = "") -> PDK: @@ -75,7 +78,7 @@ def PDK_ICS55(pdk_root: str = "") -> PDK: )) stdcell_dir = "{}/IP/STD_cell/ics55_LLSC_H7C_V1p10C100".format(resolved_root) - tech_path = "{}/prtech/techLEF/N551P6M_ecos.lef".format(resolved_root) + tech_path = "{}/prtech/techLEF/N551P6M.lef".format(resolved_root) lef_paths = [ "{}/ics55_LLSC_H7CR/lef/ics55_LLSC_H7CR_ecos.lef".format(stdcell_dir), "{}/ics55_LLSC_H7CL/lef/ics55_LLSC_H7CL_ecos.lef".format(stdcell_dir) @@ -132,3 +135,161 @@ def PDK_ICS55(pdk_root: str = "") -> PDK: ) return pdk + +def PDK_SG13G2(pdk_root: str = "") -> PDK: + resolved_root = os.path.abspath(os.path.expanduser( + (pdk_root or "").strip() + or os.environ.get("CHIPCOMPILER_SG13G2_PDK_ROOT", "").strip() + or os.environ.get("SG13G2_PDK_ROOT", "").strip() + )) + + tech_path = "{}/lef/sg13g2_tech.lef".format(resolved_root) + lef_paths = [ + "{}/lef/sg13g2_stdcell.lef".format(resolved_root) + ] + lib_paths = [ + "{}/lib/sg13g2_stdcell_typ_1p20V_25C.lib".format(resolved_root) + ] + + pdk = PDK( + name="sg13g2", + version="1.0", + root=resolved_root, + tech=tech_path if os.path.isfile(tech_path) else "", + lefs=[path for path in lef_paths if os.path.isfile(path)], + libs=[path for path in lib_paths if os.path.isfile(path)], + site_core="CoreSite", + buffers=[ + "sg13g2_buf_1", + "sg13g2_buf_2", + "sg13g2_buf_4", + "sg13g2_buf_8", + "sg13g2_buf_16" + ], + fillers=[ + "sg13g2_fill_1", + "sg13g2_fill_2", + "sg13g2_decap_4", + "sg13g2_decap_8" + ], + tie_high_cell="sg13g2_tiehi", + tie_high_port="L_HI", + tie_low_cell="sg13g2_tielo", + tie_low_port="L_LO", + dont_use=[ + "sg13g2_lgcp_1", + "sg13g2_sighold", + "sg13g2_slgcp_1", + "sg13g2_dfrbp_2" + ] + ) + + return pdk + +def PDK_GF180MCU(pdk_root: str = "") -> PDK: + resolved_root = os.path.abspath(os.path.expanduser( + (pdk_root or "").strip() + or os.environ.get("CHIPCOMPILER_GF180_PDK_ROOT", "").strip() + or os.environ.get("GF180_PDK_ROOT", "").strip() + )) + + # Standard paths for pruned GF180 distributions + tech_path = "{}/lef/gf180mcu_7t_tech.lef".format(resolved_root) + lef_paths = [ + "{}/lef/gf180mcu_fd_sc_mcu7t5v0.lef".format(resolved_root) + ] + lib_paths = [ + "{}/lib/gf180mcu_fd_sc_mcu7t5v0__ss_125C_1p65V.lib".format(resolved_root) + ] + + pdk = PDK( + name="gf180mcu", + version="1.0", + root=resolved_root, + tech=tech_path if os.path.isfile(tech_path) else "", + lefs=[path for path in lef_paths if os.path.isfile(path)], + libs=[path for path in lib_paths if os.path.isfile(path)], + site_core="GF_018_7_5_MC_TYP", + tap_cell="gf180mcu_fd_sc_mcu7t5v0__filltap", + end_cap="gf180mcu_fd_sc_mcu7t5v0__endcap", + buffers=[ + "gf180mcu_fd_sc_mcu7t5v0__buf_1", + "gf180mcu_fd_sc_mcu7t5v0__buf_2", + "gf180mcu_fd_sc_mcu7t5v0__buf_4", + "gf180mcu_fd_sc_mcu7t5v0__buf_8", + "gf180mcu_fd_sc_mcu7t5v0__buf_16" + ], + fillers=[ + "gf180mcu_fd_sc_mcu7t5v0__fill_1", + "gf180mcu_fd_sc_mcu7t5v0__fill_2", + "gf180mcu_fd_sc_mcu7t5v0__fill_4", + "gf180mcu_fd_sc_mcu7t5v0__fill_8", + "gf180mcu_fd_sc_mcu7t5v0__fill_16", + "gf180mcu_fd_sc_mcu7t5v0__fill_32" + ], + tie_high_cell="gf180mcu_fd_sc_mcu7t5v0__tieh", + tie_high_port="Z", + tie_low_cell="gf180mcu_fd_sc_mcu7t5v0__tiel", + tie_low_port="ZN", + dont_use=[ + "gf180mcu_fd_sc_mcu7t5v0__ant*", + "gf180mcu_fd_sc_mcu7t5v0__lat*", + "gf180mcu_fd_sc_mcu7t5v0__dff*" # Example: if you want to restrict DFFs + ] + ) + + return pdk + +def PDK_SKY130(pdk_root: str = "") -> PDK: + resolved_root = os.path.abspath(os.path.expanduser( + (pdk_root or "").strip() + or os.environ.get("CHIPCOMPILER_SKY130_PDK_ROOT", "").strip() + or os.environ.get("SKY130_PDK_ROOT", "").strip() + )) + + # Standard paths for sky130 high-density (hd) library + tech_path = "{}/lef/sky130_fd_sc_hd.tech.lef".format(resolved_root) + lef_paths = [ + "{}/lef/sky130_fd_sc_hd.lef".format(resolved_root) + ] + lib_paths = [ + "{}/lib/sky130_fd_sc_hd__tt_025C_1v80.lib".format(resolved_root) + ] + + pdk = PDK( + name="sky130", + version="1.0", + root=resolved_root, + tech=tech_path if os.path.isfile(tech_path) else "", + lefs=[path for path in lef_paths if os.path.isfile(path)], + libs=[path for path in lib_paths if os.path.isfile(path)], + site_core="unithd", # Standard site name for sky130_fd_sc_hd + tap_cell="sky130_fd_sc_hd__filltap_2", + end_cap="sky130_fd_sc_hd__decap_3", + buffers=[ + "sky130_fd_sc_hd__buf_1", + "sky130_fd_sc_hd__buf_2", + "sky130_fd_sc_hd__buf_4", + "sky130_fd_sc_hd__buf_8", + "sky130_fd_sc_hd__buf_12", + "sky130_fd_sc_hd__buf_16" + ], + fillers=[ + "sky130_fd_sc_hd__fill_1", + "sky130_fd_sc_hd__fill_2", + "sky130_fd_sc_hd__fill_4", + "sky130_fd_sc_hd__fill_8" + ], + # Sky130 uses the 'conb' (connect bias) cell for both tie high and low + tie_high_cell="sky130_fd_sc_hd__conb_1", + tie_high_port="HI", + tie_low_cell="sky130_fd_sc_hd__conb_1", + tie_low_port="LO", + dont_use=[ + "sky130_fd_sc_hd__ant*", # Exclude antenna cells from logic + "sky130_fd_sc_hd__lpflow*", # Exclude power management cells for basic flow + "sky130_fd_sc_hd__clkbuf_1" # Usually too small for clock trees + ] + ) + + return pdk \ No newline at end of file