Files
retroSoC/physical/ecc/scripts/generate_config.py
T
maksyuki 87df13fb46 feat: add ECC flow for padless ICS55 core hardening
- Introduced a new ECC directory containing scripts and Makefile for the padless ICS55 core hardening flow.
- Updated the main Makefile to include the new ECC Makefile and added relevant help commands.
- Added dependencies for the ECC CLI in the dependencies.lock.json file.
- Created README documentation for the ECC flow detailing usage and requirements.
- Implemented various scripts for configuration generation, validation, output checking, and packaging of ECC results.
- Added unit tests to validate the ECC configuration and flow behavior.
2026-08-25 20:02:58 +08:00

108 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Generate a padless ICS55 ECC project configuration from canonical inputs."""
from __future__ import annotations
import argparse
import os
from pathlib import Path
EXPECTED_CLOCKS = (
"clk_external",
"clk_system",
"clk_audio",
"clk_jtag",
"clk_dvp",
"clk_usb2_ulpi",
)
def relative(path: Path, base: Path) -> str:
return os.path.relpath(path.resolve(), base.resolve())
def render(args: argparse.Namespace) -> str:
project_dir = args.output.resolve().parent
pdk_root = args.pdk_root.resolve()
sdc = args.sdc.resolve()
liberty = args.h7cr_liberty.resolve()
tech = pdk_root / "prtech/techLEF/N551P6M_ecos.lef"
lef = (
pdk_root
/ "IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/lef/"
"ics55_LLSC_H7CR_ecos.lef"
)
required = (args.rtl.resolve(), sdc, pdk_root, tech, lef, liberty)
missing = [str(path) for path in required if not path.exists()]
if missing:
raise FileNotFoundError("missing ECC configuration input(s): " + ", ".join(missing))
sdc_text = sdc.read_text(encoding="utf-8")
missing_clocks = [clock for clock in EXPECTED_CLOCKS if f"-name {clock}" not in sdc_text]
if missing_clocks:
raise ValueError("ECC SDC is missing clock(s): " + ", ".join(missing_clocks))
return "\n".join(
(
"# Generated by physical/ecc/scripts/generate_config.py; do not edit.",
"[design]",
'name = "retrosoc_core"',
'top = "retrosoc_core"',
f'rtl = ["{relative(args.rtl, project_dir)}"]',
'clock_port = "extclk_i_pad"',
f"frequency_mhz = {args.ext_clk_hz / 1_000_000:.9g}",
"",
"[pdk]",
'name = "ics55"',
f'root = "{relative(pdk_root, project_dir)}"',
"",
"# ECC v0.1.0-alpha.10 resolves PDK content paths relative to pdk.root.",
"# Supply only the padless H7CR core library and the generated multi-clock SDC.",
"[pdk.overrides]",
f'tech = "{relative(tech, pdk_root)}"',
f'lefs = ["{relative(lef, pdk_root)}"]',
f'libs = ["{relative(liberty, pdk_root)}"]',
f'sdc = "{relative(sdc, project_dir)}"',
'site_core = "core7"',
'tap_cell = "FILLTAPH7R"',
'end_cap = "FILLTAPH7R"',
'fillers = ["FILLER64H7R", "FILLER32H7R", "FILLER16H7R", "FILLER8H7R", "FILLER4H7R", "FILLER2H7R", "FILLER1H7R"]',
"",
"[flow]",
'preset = "harden"',
'run = "default"',
"",
"[params.floorplan]",
"core_util = 0.60",
"aspect_ratio = 1.0",
"",
"[params.place]",
"target_density = 0.55",
"",
)
)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--rtl", type=Path, required=True)
parser.add_argument("--sdc", type=Path, required=True)
parser.add_argument("--pdk-root", type=Path, required=True)
parser.add_argument("--h7cr-liberty", type=Path, required=True)
parser.add_argument("--ext-clk-hz", type=int, required=True)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
if args.ext_clk_hz <= 0:
parser.error("--ext-clk-hz must be positive")
try:
content = render(args)
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(content, encoding="utf-8")
except (OSError, ValueError) as error:
parser.error(str(error))
return 0
if __name__ == "__main__":
raise SystemExit(main())