Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 74 additions & 7 deletions chipcompiler/data/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,74 @@
]
}
}
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": "",
"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"]}
]
}
}

ICS55_DESIGN_PARAMETERS = {
"gcd": {
Expand Down Expand Up @@ -227,20 +295,19 @@ def save_parameter(parameter : Parameters) -> bool:
return json_write(file_path=parameter.path,
data=parameter.data)

def get_parameters(pdk_name : str = "", path : str = "") -> Parameters:
"""
Return the Parameters instance based on the given pdk name.
"""
def get_parameters(pdk_name: str = "", path: str = "") -> Parameters:
if os.path.isfile(path):
return load_parameter(path)

parameters = Parameters()
parameters.path = path

match pdk_name.lower():
case "ics55":
parameters.data = deepcopy(ICS55_PARAMETERS_TEMPLATE)

case "sg13g2":
parameters.data = deepcopy(SG13G2_PARAMETERS_TEMPLATE)

return parameters

def get_design_parameters(pdk_name : str, design : str = "", path : str = "") -> Parameters:
Expand Down
52 changes: 52 additions & 0 deletions chipcompiler/data/pdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ def get_pdk(pdk_name : str, pdk_root: str = "") -> PDK:
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)
else:
pdk = PDK(name=pdk_name_normalized)
pdk.validate()
Expand Down Expand Up @@ -132,3 +134,53 @@ 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 = "{}/libs.ref/sg13g2_stdcell/lef/sg13g2_tech.lef".format(resolved_root)
lef_paths = [
"{}/libs.ref/sg13g2_stdcell/lef/sg13g2_stdcell.lef".format(resolved_root)
]
lib_paths = [
"{}/libs.ref/sg13g2_stdcell/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
86 changes: 86 additions & 0 deletions test/test_data_pdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,89 @@ def test_get_pdk_raises_on_missing_pdk_files(tmp_path):

with pytest.raises(ValueError, match="PDK validation failed"):
get_pdk("ics55", pdk_root=str(invalid_root))


#SG13G2 helpers and tests

def _create_minimal_sg13g2_pdk(root: Path) -> Path:
"""Create the minimal SG13G2 directory tree required by get_pdk()."""
tech_path = root / "libs.ref" / "sg13g2_stdcell" / "lef" / "sg13g2_tech.lef"
tech_path.parent.mkdir(parents=True, exist_ok=True)
tech_path.write_text("VERSION 5.8 ;\n")

lef_path = root / "libs.ref" / "sg13g2_stdcell" / "lef" / "sg13g2_stdcell.lef"
lef_path.write_text("VERSION 5.8 ;\n")

lib_path = root / "libs.ref" / "sg13g2_stdcell" / "lib" / "sg13g2_stdcell_typ_1p20V_25C.lib"
lib_path.parent.mkdir(parents=True, exist_ok=True)
lib_path.write_text("library(test) { }\n")

return root


def test_get_pdk_sg13g2_prefers_explicit_root_over_env(tmp_path, monkeypatch):
explicit_root = _create_minimal_sg13g2_pdk(tmp_path / "explicit")
env_root = _create_minimal_sg13g2_pdk(tmp_path / "env")
monkeypatch.setenv("CHIPCOMPILER_SG13G2_PDK_ROOT", str(env_root))

pdk = get_pdk("sg13g2", pdk_root=str(explicit_root))

expected_root = str(explicit_root.resolve())
assert pdk.root == expected_root
assert pdk.tech.startswith(expected_root)
assert all(path.startswith(expected_root) for path in pdk.lefs + pdk.libs)


def test_get_pdk_sg13g2_uses_namespaced_env(tmp_path, monkeypatch):
env_root = _create_minimal_sg13g2_pdk(tmp_path / "env")
monkeypatch.setenv("CHIPCOMPILER_SG13G2_PDK_ROOT", str(env_root))
monkeypatch.delenv("SG13G2_PDK_ROOT", raising=False)

pdk = get_pdk("sg13g2")

assert pdk.root == str(env_root.resolve())


def test_get_pdk_sg13g2_uses_legacy_env_when_namespaced_missing(tmp_path, monkeypatch):
legacy_root = _create_minimal_sg13g2_pdk(tmp_path / "legacy")
monkeypatch.delenv("CHIPCOMPILER_SG13G2_PDK_ROOT", raising=False)
monkeypatch.setenv("SG13G2_PDK_ROOT", str(legacy_root))

pdk = get_pdk("sg13g2")

assert pdk.root == str(legacy_root.resolve())


def test_get_pdk_sg13g2_raises_on_missing_pdk_files(tmp_path, monkeypatch):
invalid_root = tmp_path / "broken_sg13g2"
invalid_root.mkdir(parents=True, exist_ok=True)
monkeypatch.setenv("CHIPCOMPILER_SG13G2_PDK_ROOT", str(invalid_root))

with pytest.raises(ValueError, match="PDK validation failed"):
get_pdk("sg13g2")


def test_get_pdk_sg13g2_cell_config(tmp_path, monkeypatch):
pdk_root = _create_minimal_sg13g2_pdk(tmp_path / "sg13g2")
monkeypatch.setenv("CHIPCOMPILER_SG13G2_PDK_ROOT", str(pdk_root))

pdk = get_pdk("sg13g2")

assert pdk.name == "sg13g2"
assert pdk.site_core == "CoreSite"
assert pdk.tie_high_cell == "sg13g2_tiehi"
assert pdk.tie_high_port == "L_HI"
assert pdk.tie_low_cell == "sg13g2_tielo"
assert pdk.tie_low_port == "L_LO"
assert "sg13g2_buf_1" in pdk.buffers
assert "sg13g2_fill_1" in pdk.fillers
assert "sg13g2_lgcp_1" in pdk.dont_use


def test_get_pdk_sg13g2_case_insensitive(tmp_path, monkeypatch):
pdk_root = _create_minimal_sg13g2_pdk(tmp_path / "sg13g2")
monkeypatch.setenv("CHIPCOMPILER_SG13G2_PDK_ROOT", str(pdk_root))

pdk = get_pdk("SG13G2")

assert pdk.name == "sg13g2"
64 changes: 64 additions & 0 deletions test/test_design_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,67 @@ def test_ics55_template_has_dreamplace_padding_defaults():

assert parameters.data["Cell padding x"] == 600
assert parameters.data["Routability opt flag"] == 1


#SG13G2 parameter tests

def test_get_parameters_sg13g2_returns_template():
parameters = get_parameters("sg13g2")

assert parameters.data["PDK"] == "sg13g2"
assert parameters.data["Design"] == ""
assert parameters.data["Top module"] == ""
assert parameters.data["Clock"] == ""
assert parameters.data["Frequency max [MHz]"] == 100


def test_get_parameters_sg13g2_returns_independent_copies():
first = get_parameters("sg13g2")
second = get_parameters("sg13g2")

first.data["Design"] = "mutated"
first.data["Floorplan"]["Tracks"][0]["x step"] = 999

assert second.data["Design"] == ""
assert second.data["Floorplan"]["Tracks"][0]["x step"] == 420


def test_sg13g2_template_has_correct_layer_names():
parameters = get_parameters("sg13g2")

assert parameters.data["Bottom layer"] == "Metal2"
assert parameters.data["Top layer"] == "Metal5"


def test_sg13g2_template_has_correct_core_defaults():
parameters = get_parameters("sg13g2")

assert parameters.data["Core"]["Utilitization"] == 0.65
assert parameters.data["Core"]["Margin"] == [17.5, 17.5]
assert parameters.data["Target density"] == 0.65


def test_sg13g2_template_has_dreamplace_padding_defaults():
parameters = get_parameters("sg13g2")

assert parameters.data["Cell padding x"] == 0
assert parameters.data["Routability opt flag"] == 1


def test_sg13g2_template_pdn_has_two_power_nets():
parameters = get_parameters("sg13g2")

io_nets = parameters.data["PDN"]["IO"]
assert len(io_nets) == 2
net_names = [n["net name"] for n in io_nets]
assert "VDD" in net_names
assert "VSS" in net_names


def test_get_design_parameters_sg13g2_returns_base_template():
"""SG13G2 has no design-specific overrides, so any design name returns the base template."""
parameters = get_design_parameters("sg13g2", "gcd")

assert parameters.data["PDK"] == "sg13g2"
assert parameters.data["Design"] == ""
assert parameters.data["Top module"] == ""
35 changes: 35 additions & 0 deletions test/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,42 @@ def test_ics55_gcd():

engine_flow.run_steps()

def test_sg13g2_gcd():
workspace_dir="{}/test/examples/sg13g2_gcd_tool".format(root)

input_def = ""
input_verilog = "{}/test/fixtures/gcd/gcd.v".format(root) # RTL file
parameters=get_design_parameters("sg13g2", "gcd")
parameters.data["Design"] = "gcd"
parameters.data["Top module"] = "gcd"
parameters.data["Clock"] = "clk"

pdk_root = "{}/ihp-sg13g2".format(root)
pdk = get_pdk("sg13g2", pdk_root=pdk_root)

workspace = create_workspace(
directory=workspace_dir,
origin_def=input_def,
origin_verilog=input_verilog,
pdk=pdk,
parameters=parameters
)


engine_flow = EngineFlow(workspace=workspace)
if not engine_flow.has_init():
from chipcompiler.rtl2gds import build_rtl2gds_flow
steps = build_rtl2gds_flow()
for step, tool, state in steps:
engine_flow.add_step(step=step, tool=tool, state=state)

engine_flow.create_step_workspaces()

engine_flow.run_steps()


if __name__ == "__main__":
test_ics55_gcd()
test_sg13g2_gcd()

exit(0)
Loading