mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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.
This commit is contained in:
131 files changed
+5983
-1790
No files matched your search
@@ -12,8 +12,10 @@ from typing import Any
|
||||
|
||||
RESET_PRIMITIVES = {"rst_sync"}
|
||||
CDC_PRIMITIVES = {
|
||||
"apb4_async_bridge",
|
||||
"async_fifo",
|
||||
"async_reqack",
|
||||
"axi4_async_bridge",
|
||||
"cdc_2phase",
|
||||
"cdc_fifo",
|
||||
"cdc_sync",
|
||||
|
||||
@@ -100,10 +100,9 @@ def render_active_manifest(manifest_path: Path, extensions_path: Path) -> str:
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def generate(root: Path, output: Path) -> None:
|
||||
def generate(root: Path, output: Path, extensions: Path) -> None:
|
||||
managed_mpw = root / "rtl/managed/mpw"
|
||||
manifest = managed_mpw / "mpw.toml"
|
||||
extensions = root / "rtl/mini/integration/user_extensions.json"
|
||||
if not manifest.is_file():
|
||||
raise FileNotFoundError(f"MPW v2 manifest is missing: {manifest}")
|
||||
descriptor, manifest_name = tempfile.mkstemp(
|
||||
@@ -126,12 +125,11 @@ def generate(root: Path, output: Path) -> None:
|
||||
subprocess.run(command, cwd=managed_mpw, check=True)
|
||||
finally:
|
||||
active_manifest.unlink(missing_ok=True)
|
||||
validate_extension_bindings(root, output)
|
||||
validate_extension_bindings(extensions, output)
|
||||
|
||||
|
||||
def validate_extension_bindings(root: Path, output: Path) -> None:
|
||||
def validate_extension_bindings(extensions_path: Path, output: Path) -> None:
|
||||
"""Require SoC slot bindings to match the generated MPW v2 manifest."""
|
||||
extensions_path = root / "rtl/mini/integration/user_extensions.json"
|
||||
manifest_path = output / "manifest.json"
|
||||
extensions = json.loads(extensions_path.read_text(encoding="utf-8"))
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
@@ -178,12 +176,17 @@ def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--root", required=True, type=Path)
|
||||
parser.add_argument("--output", required=True, type=Path)
|
||||
parser.add_argument("--extensions", required=True, type=Path)
|
||||
parser.add_argument("--lock-file", required=True, type=Path)
|
||||
arguments = parser.parse_args()
|
||||
arguments.lock_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with arguments.lock_file.open("a+", encoding="utf-8") as lock:
|
||||
fcntl.flock(lock, fcntl.LOCK_EX)
|
||||
generate(arguments.root.resolve(), arguments.output.resolve())
|
||||
generate(
|
||||
arguments.root.resolve(),
|
||||
arguments.output.resolve(),
|
||||
arguments.extensions.resolve(),
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -59,16 +59,23 @@ def generate(args: argparse.Namespace) -> None:
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
command = [
|
||||
str(args.sbt),
|
||||
"--batch",
|
||||
f'set Compile / unmanagedSourceDirectories += file("{scala_dir}")',
|
||||
f"runMain {GENERATOR_CLASS} {output}",
|
||||
]
|
||||
environment = os.environ.copy()
|
||||
java_home = environment.get("HOME")
|
||||
if java_home:
|
||||
inherited = environment.get("JAVA_TOOL_OPTIONS", "").strip()
|
||||
environment["JAVA_TOOL_OPTIONS"] = (
|
||||
f"{inherited} -Duser.home={java_home}".strip()
|
||||
)
|
||||
sbt_cache = root / ".cache/retrosoc/sbt"
|
||||
sbt_cache.mkdir(parents=True, exist_ok=True)
|
||||
inherited = environment.get("JAVA_TOOL_OPTIONS", "").strip()
|
||||
java_options = (
|
||||
f"-Duser.home={sbt_cache} "
|
||||
f"-Dsbt.global.base={sbt_cache / 'global'} "
|
||||
f"-Dsbt.boot.directory={sbt_cache / 'boot'} "
|
||||
f"-Dsbt.ivy.home={sbt_cache / 'ivy'}"
|
||||
" -Dsbt.server.autostart=false"
|
||||
)
|
||||
environment["JAVA_TOOL_OPTIONS"] = f"{inherited} {java_options}".strip()
|
||||
environment["COURSIER_CACHE"] = str(sbt_cache / "coursier")
|
||||
subprocess.run(command, cwd=source, check=True, env=environment)
|
||||
|
||||
generated = output / "vexii_riscv_hp_generated.v"
|
||||
|
||||
+22
-2
@@ -101,6 +101,26 @@ def main() -> int:
|
||||
staging = Path(temp) / "package"
|
||||
staging.mkdir()
|
||||
timing_contract = Path(temp) / "commercial_timing_contract.tcl"
|
||||
if config.get("MINI_MODE", "PRODUCT") == "MPW":
|
||||
dynamic_core_filelist = (
|
||||
args.variant_root
|
||||
/ "generated/mpw"
|
||||
/ config["SIMU"].lower()
|
||||
/ "core/core.fl"
|
||||
)
|
||||
dynamic_ip_filelist = (
|
||||
args.variant_root
|
||||
/ "generated/mpw"
|
||||
/ config["SIMU"].lower()
|
||||
/ "ip/ip.fl"
|
||||
)
|
||||
else:
|
||||
dynamic_core_filelist = (
|
||||
args.variant_root / "generated/user_extensions/legacy_core.fl"
|
||||
)
|
||||
dynamic_ip_filelist = (
|
||||
args.variant_root / "generated/user_extensions/legacy_ip.fl"
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
"python3",
|
||||
@@ -137,9 +157,9 @@ def main() -> int:
|
||||
"--clint-timebase-hz",
|
||||
str(config.get("CLINT_TIMEBASE_HZ", 1_000_000)),
|
||||
"--dynamic-core-filelist",
|
||||
str(args.variant_root / "generated/mpw" / config["SIMU"].lower() / "core/core.fl"),
|
||||
str(dynamic_core_filelist),
|
||||
"--dynamic-ip-filelist",
|
||||
str(args.variant_root / "generated/mpw" / config["SIMU"].lower() / "ip/ip.fl"),
|
||||
str(dynamic_ip_filelist),
|
||||
"--memory-map-filelist",
|
||||
str(args.variant_root / "generated/memory_map/memory_map.fl"),
|
||||
"--soc-topology-filelist",
|
||||
|
||||
@@ -33,6 +33,8 @@ TEST_SOURCES = (
|
||||
"crt/src/hal/i2s_math.c",
|
||||
"crt/src/hal/dma_math.c",
|
||||
"crt/src/hal/sysctrl.c",
|
||||
"crt/src/hal/clock.c",
|
||||
"crt/src/hal/extension.c",
|
||||
"crt/src/hal/user_ip.c",
|
||||
"rtl/managed/clusterip/ps2/sw/src/ps2.c",
|
||||
"rtl/managed/clusterip/ps2/sw/src/ps2_keyboard.c",
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install the locked VexiiRiscv source used by Mini product profiles."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from dependency_lock import source
|
||||
from setup_helpers import ensure_git_repo, run
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def repair_incomplete_checkout(destination: Path, url: str, revision: str) -> None:
|
||||
if not (destination / ".git").is_dir():
|
||||
return
|
||||
result = subprocess.run(
|
||||
["git", "-C", str(destination), "rev-parse", "--verify", "HEAD"],
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return
|
||||
run(("git", "remote", "set-url", "origin", url), cwd=destination)
|
||||
run(("git", "fetch", "--depth", "1", "origin", revision), cwd=destination)
|
||||
run(("git", "checkout", "--detach", "FETCH_HEAD"), cwd=destination)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--update", action="store_true")
|
||||
args = parser.parse_args()
|
||||
dependency = source("vexiiriscv")
|
||||
destination = ROOT / dependency["destination"]
|
||||
repair_incomplete_checkout(destination, dependency["url"], dependency["revision"])
|
||||
ensure_git_repo(
|
||||
dependency["url"],
|
||||
destination,
|
||||
dependency["revision"],
|
||||
recursive=dependency.get("recursive", False),
|
||||
update=args.update,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -22,7 +22,7 @@ def require_string(value: Any, field: str) -> str:
|
||||
return value
|
||||
|
||||
|
||||
def period_ps(document: dict[str, Any], domain: str = "external") -> int:
|
||||
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:
|
||||
@@ -42,7 +42,7 @@ def period_ps(document: dict[str, Any], domain: str = "external") -> int:
|
||||
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")
|
||||
parser.add_argument("--domain", default="hp")
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user