mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
refactor: refactor Yosys synthesis flow to support multiple recipes
- Introduced SYNTH_RECIPE variable to select between balanced, area, and speed synthesis recipes. - Updated Makefile to handle new SYNTH_RECIPE variable and its validation. - Modified synthesis scripts to utilize the selected recipe, ensuring outputs are directed to the appropriate directories. - Enhanced documentation to reflect changes in synthesis flow and directory structure. - Added tests to verify correct behavior of new synthesis recipes and their integration into the regression suite. - Removed obsolete scripts and configurations related to previous synthesis methods.
This commit is contained in:
23 files changed
+391
-232
No files matched your search
@@ -65,6 +65,8 @@ NIGHTLY_COMMANDS = (
|
||||
"configs/benchmark/ihp130-hazard3-coremark.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "coremark-report"),
|
||||
),
|
||||
("configs/ci/ihp130.mk", ("SYNTH=YOSYS", "SYNTH_RECIPE=area", "synth")),
|
||||
("configs/ci/ihp130.mk", ("SYNTH=YOSYS", "SYNTH_RECIPE=speed", "synth")),
|
||||
)
|
||||
PR_PROFILES = ("configs/ci/ihp130.mk",)
|
||||
SMOKE_PROFILES: tuple[str, ...] = ()
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Derive the Yosys ABC target period from the SoC clock/reset inventory."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
def require_object(value: Any, field: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError(f"{field} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def require_string(value: Any, field: str) -> str:
|
||||
if not isinstance(value, str) or not value:
|
||||
raise ValueError(f"{field} must be a non-empty string")
|
||||
return value
|
||||
|
||||
|
||||
def period_ps(document: dict[str, Any], domain: str = "external") -> int:
|
||||
require_string(domain, "domain")
|
||||
domains = document.get("domains")
|
||||
if not isinstance(domains, list) or not domains:
|
||||
raise ValueError("domains must be a non-empty list")
|
||||
for entry in domains:
|
||||
item = require_object(entry, "domains entry")
|
||||
if item.get("name") != domain:
|
||||
continue
|
||||
sta = require_object(item.get("sta"), f"domain {domain}.sta")
|
||||
period_ns = sta.get("period_ns")
|
||||
if not isinstance(period_ns, (int, float)) or isinstance(period_ns, bool) or period_ns <= 0:
|
||||
raise ValueError(f"domain {domain}.sta.period_ns must be a positive number")
|
||||
return round(float(period_ns) * 1000)
|
||||
raise ValueError(f"domain {domain} is not declared")
|
||||
|
||||
|
||||
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--domains", type=Path, required=True)
|
||||
parser.add_argument("--domain", default="external")
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(argv)
|
||||
try:
|
||||
document = require_object(
|
||||
json.loads(args.domains.read_text(encoding="utf-8")), "domain map"
|
||||
)
|
||||
print(period_ps(document, args.domain))
|
||||
except (OSError, ValueError, json.JSONDecodeError) as error:
|
||||
print(error, file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user