Files
retroSoC/scripts/yosys_period.py
T
maksyuki 2b6819449c feat: enhance test coverage and update system control interfaces
- Added  interface to  and implemented error handling for register writes.
- Introduced a new test for AXI4 address gate functionality in .
- Updated clock and reset domain assertions in  to reflect new domain names.
- Modified expected outputs in  to include new clock domains.
- Adjusted chip configuration assertions in  to account for additional power pads.
- Enhanced memory map tests in  with new definitions and includes.
- Updated pin mapping tests in  to include new reference clock pads.
- Improved script tools tests in  to ensure correct validation of extension bindings.
- Refined system control tests in  to include new clock control interface.
- Updated USB2 packet RAM tests in  to include new SRAM definitions.
- Enhanced user extensions tests in  to validate new product extension configurations.
- Adjusted user IP register parity tests to use legacy extensions.
- Updated Yosys synthesis recipe tests to reflect changes in STA period calculations.
2026-08-30 08:10:59 +08:00

64 lines
2.1 KiB
Python
Executable File

#!/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 = "hp") -> 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="hp")
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())