mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: refactor NMI interface and remove unused variables
- Removed CORE and IP variables from common.tcl and synth.tcl scripts. - Updated yosys.mk to exclude CORE and IP from environment variables. - Modified bus_fault_tb to enhance NMI interface with management and user NMI signals. - Added user access denial handling in bus_fault_tb. - Updated pll_ctrl_tb and sysctrl_fault_tb to reflect changes in NMI interface. - Adjusted test_gpio_user_mux.py to remove IP_MDD definition. - Enhanced memory map tests to include user extensions and ensure proper generation. - Updated test_script_tools.py to reflect changes in core management and user extensions. - Refined topology tests to ensure user APB target is always added. - Adjusted tech cell configuration tests to use simplified profile paths. - Improved user extensions tests for scalar bindings and slot validation.
This commit is contained in:
111 files changed
+3729
-2012
No files matched your search
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import posixpath
|
||||
import re
|
||||
import sys
|
||||
from collections import Counter
|
||||
@@ -26,6 +27,10 @@ LOCATION_RE = re.compile(
|
||||
r"(?:c|cc|cpp|cxx|h|hpp|py|sv|svh|tcl|v|vh)):\d+(?::\d+)?",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
GENERATED_MPW_PATH_RE = re.compile(
|
||||
r"\$BUILD/generated/mpw/[A-Za-z0-9_-]+/(?P<tree>core|ip)/(?P<path>[^\s:]+)"
|
||||
)
|
||||
MPW_INSTANCE_FILE_SUFFIX_RE = re.compile(r"_username[0-9]+(?=\.(?:sv|svh|v|vh)$)")
|
||||
|
||||
|
||||
def warning_line(tool: str, line: str) -> tuple[str, str] | None:
|
||||
@@ -58,11 +63,19 @@ def normalize(root: Path, identifier: str, message: str) -> str:
|
||||
value,
|
||||
)
|
||||
value = value.replace(resolved_root, "$ROOT")
|
||||
value = GENERATED_MPW_PATH_RE.sub(_normalize_generated_mpw_path, value)
|
||||
value = LOCATION_RE.sub(lambda match: match.group("path") + ":<line>", value)
|
||||
value = re.sub(r"\s+", " ", value)
|
||||
return f"{identifier}:{value}"
|
||||
|
||||
|
||||
def _normalize_generated_mpw_path(match: re.Match[str]) -> str:
|
||||
"""Map isolated MPW copies back to their managed source locations."""
|
||||
relative_path = posixpath.normpath(match.group("path"))
|
||||
relative_path = MPW_INSTANCE_FILE_SUFFIX_RE.sub("", relative_path)
|
||||
return f"$ROOT/rtl/managed/mpw/{match.group('tree')}/{relative_path}"
|
||||
|
||||
|
||||
def scan(tool: str, logs: list[Path], root: Path) -> dict[str, object]:
|
||||
counts: Counter[str] = Counter()
|
||||
examples: dict[str, str] = {}
|
||||
|
||||
@@ -23,8 +23,6 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--synth", required=True)
|
||||
parser.add_argument("--sta", required=True)
|
||||
parser.add_argument("--pdk", required=True)
|
||||
parser.add_argument("--core", required=True)
|
||||
parser.add_argument("--ip", required=True)
|
||||
parser.add_argument("--formal", choices=("YES", "NO"), default="NO")
|
||||
parser.add_argument("--lock", type=Path, default=DEFAULT_LOCK)
|
||||
parser.add_argument("--format", choices=("text", "json"), default="text")
|
||||
|
||||
+25
-28
@@ -83,6 +83,17 @@ def migrate_user_gpio_interfaces(root: Path) -> list[Path]:
|
||||
return migrated
|
||||
|
||||
|
||||
def remove_legacy_picorv32_entry(filelist: Path, management_core_dir: Path) -> None:
|
||||
"""Remove the PicoRV32 line emitted by the legacy user-core generator."""
|
||||
excluded = {
|
||||
str((management_core_dir / "picorv32.v").resolve()),
|
||||
str((management_core_dir / "picorv32_ver.v").resolve()),
|
||||
}
|
||||
content = filelist.read_text(encoding="utf-8")
|
||||
filtered = [line for line in content.splitlines() if line.strip() not in excluded]
|
||||
filelist.write_text("\n".join(filtered) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def remove_tree(path: Path) -> None:
|
||||
"""Remove an MPW workspace, tolerating transient NFS directory entries."""
|
||||
for attempt in range(3):
|
||||
@@ -126,41 +137,28 @@ def generate(args: argparse.Namespace) -> None:
|
||||
root = args.root.resolve()
|
||||
managed_mpw = root / "rtl/managed/mpw"
|
||||
output = args.output.resolve()
|
||||
needs_core = args.core == "MDD"
|
||||
needs_ip = args.ip == "MDD"
|
||||
log_path = output.parent / f"{output.name}-generation.log"
|
||||
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log_path.open("w", encoding="utf-8") as log, temporary_workspace(
|
||||
output.parent, f".{output.name}."
|
||||
) as workspace:
|
||||
log.write(f"simulator={args.simu} core={args.core} ip={args.ip}\n")
|
||||
with (
|
||||
log_path.open("w", encoding="utf-8") as log,
|
||||
temporary_workspace(output.parent, f".{output.name}.") as workspace,
|
||||
):
|
||||
log.write(f"simulator={args.simu} user-extensions=enabled\n")
|
||||
candidate = workspace / "output"
|
||||
candidate.mkdir()
|
||||
if not needs_core and not needs_ip:
|
||||
if tree_digest(candidate) == tree_digest(output):
|
||||
print(f"[mpw] generated output unchanged: {output} (log: {log_path})")
|
||||
return
|
||||
if output.exists():
|
||||
shutil.rmtree(output)
|
||||
os.replace(candidate, output)
|
||||
print(f"[mpw] generated isolated output: {output} (log: {log_path})")
|
||||
return
|
||||
|
||||
mpw = prepare_legacy_mpw_workspace(root, managed_mpw, workspace)
|
||||
shared = mpw / ".build"
|
||||
(shared / "user_design_info.h").unlink(missing_ok=True)
|
||||
|
||||
if needs_ip:
|
||||
run(workspace, log, mpw / "ip.py")
|
||||
run(workspace, log, mpw / "info.py", "IP")
|
||||
shutil.copytree(shared / "ip", candidate / "ip")
|
||||
migrated = migrate_user_gpio_interfaces(candidate / "ip")
|
||||
log.write(f"migrated user GPIO interfaces: {len(migrated)}\n")
|
||||
if needs_core:
|
||||
run(workspace, log, mpw / "core.py", args.simu)
|
||||
run(workspace, log, mpw / "info.py", "CORE")
|
||||
shutil.copytree(shared / "core", candidate / "core")
|
||||
run(workspace, log, mpw / "ip.py")
|
||||
run(workspace, log, mpw / "info.py", "IP")
|
||||
shutil.copytree(shared / "ip", candidate / "ip")
|
||||
migrated = migrate_user_gpio_interfaces(candidate / "ip")
|
||||
log.write(f"migrated user GPIO interfaces: {len(migrated)}\n")
|
||||
run(workspace, log, mpw / "core.py", args.simu)
|
||||
run(workspace, log, mpw / "info.py", "CORE")
|
||||
shutil.copytree(shared / "core", candidate / "core")
|
||||
info = shared / "user_design_info.h"
|
||||
if info.is_file():
|
||||
shutil.copy2(info, candidate / info.name)
|
||||
@@ -172,6 +170,7 @@ def generate(args: argparse.Namespace) -> None:
|
||||
(workspace / "rtl" / "mini" / "core", root / "rtl/managed/picorv32/rtl"),
|
||||
),
|
||||
)
|
||||
remove_legacy_picorv32_entry(candidate / "core/core.fl", root / "rtl/managed/picorv32/rtl")
|
||||
if tree_digest(candidate) == tree_digest(output):
|
||||
print(f"[mpw] generated output unchanged: {output} (log: {log_path})")
|
||||
return
|
||||
@@ -186,8 +185,6 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--root", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--simu", choices=("VCS", "VERILATOR", "IVERILOG"), required=True)
|
||||
parser.add_argument("--core", choices=("PICORV32", "HAZARD3", "MDD"), required=True)
|
||||
parser.add_argument("--ip", choices=("NONE", "MDD"), required=True)
|
||||
parser.add_argument("--lock-file", type=Path, required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
+26
-7
@@ -43,7 +43,9 @@ def make_sbom(lock: dict[str, object]) -> dict[str, object]:
|
||||
components = [component(name, "source", spec) for name, spec in lock["sources"].items()]
|
||||
components.extend(component(name, "archive", spec) for name, spec in lock["archives"].items())
|
||||
for platform, tools in lock["toolchains"].items():
|
||||
components.extend(component(f"{platform}/{name}", "toolchain", spec) for name, spec in tools.items())
|
||||
components.extend(
|
||||
component(f"{platform}/{name}", "toolchain", spec) for name, spec in tools.items()
|
||||
)
|
||||
return {
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
@@ -66,19 +68,34 @@ def main() -> int:
|
||||
lock = load_lock(args.lock)
|
||||
args.output_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="retrosoc-package-", dir=args.output_dir.parent) as temp:
|
||||
with tempfile.TemporaryDirectory(
|
||||
prefix="retrosoc-package-", dir=args.output_dir.parent
|
||||
) as temp:
|
||||
staging = Path(temp) / "package"
|
||||
staging.mkdir()
|
||||
command = [
|
||||
"python3", str(root / "syn/tools/export_soc_sources.py"), "sv",
|
||||
"--output-dir", str(staging), "--pdk", config["PDK"],
|
||||
"--core", config["CORE"], "--ip", config["IP"], "--simu", config["SIMU"],
|
||||
"python3",
|
||||
str(root / "syn/tools/export_soc_sources.py"),
|
||||
"sv",
|
||||
"--output-dir",
|
||||
str(staging),
|
||||
"--pdk",
|
||||
config["PDK"],
|
||||
"--simu",
|
||||
config["SIMU"],
|
||||
"--core",
|
||||
config.get("CORE", "HAZARD3"),
|
||||
"--dynamic-core-filelist",
|
||||
str(args.variant_root / "generated/mpw" / config["SIMU"].lower() / "core/core.fl"),
|
||||
"--dynamic-ip-filelist",
|
||||
str(args.variant_root / "generated/mpw" / config["SIMU"].lower() / "ip/ip.fl"),
|
||||
]
|
||||
for key, flag in (("HAVE_PLL", "--have-pll"), ("HAVE_SRAM_IF", "--have-sram-if"), ("HAVE_SRAM_MACRO", "--have-sram-macro"), ("HAVE_SVA", "--have-sva")):
|
||||
for key, flag in (
|
||||
("HAVE_PLL", "--have-pll"),
|
||||
("HAVE_SRAM_IF", "--have-sram-if"),
|
||||
("HAVE_SRAM_MACRO", "--have-sram-macro"),
|
||||
("HAVE_SVA", "--have-sva"),
|
||||
):
|
||||
if config.get(key) == "YES":
|
||||
command.append(flag)
|
||||
subprocess.run(command, cwd=root, check=True)
|
||||
@@ -87,7 +104,9 @@ def main() -> int:
|
||||
shutil.rmtree(staging / "rtl")
|
||||
shutil.copy2(args.lock, staging / "dependencies.lock.json")
|
||||
shutil.copy2(manifest_path, staging / "manifest.json")
|
||||
(staging / "sbom.cdx.json").write_text(json.dumps(make_sbom(lock), indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
(staging / "sbom.cdx.json").write_text(
|
||||
json.dumps(make_sbom(lock), indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||
)
|
||||
checksums = []
|
||||
for path in sorted(item for item in staging.iterdir() if item.is_file()):
|
||||
checksums.append(f"{hashlib.sha256(path.read_bytes()).hexdigest()} {path.name}")
|
||||
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# Publish the archive pinned by config/dependencies.lock.json to retroSoC/artifact.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
readonly REPOSITORY="retroSoC/artifact"
|
||||
readonly RELEASE_TAG="fatfs-r0.16"
|
||||
readonly ASSET_NAME="fatfs-r0.16.zip"
|
||||
readonly ARCHIVE_SHA256="99f7dc1f7e095356e4a9e3dbe29959090d8b948afe2bbc5441e52fdf4b85449e"
|
||||
readonly ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
readonly SOURCE_ARCHIVE="${1:-${ROOT_DIR}/app/fatfs/ff16/ff16.zip}"
|
||||
|
||||
command -v gh >/dev/null
|
||||
gh auth status --hostname github.com
|
||||
|
||||
if [[ ! -f "${SOURCE_ARCHIVE}" ]]; then
|
||||
printf 'FatFs archive not found: %s\n' "${SOURCE_ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
actual_sha256="$(sha256sum "${SOURCE_ARCHIVE}" | awk '{print $1}')"
|
||||
if [[ "${actual_sha256}" != "${ARCHIVE_SHA256}" ]]; then
|
||||
printf 'FatFs archive checksum mismatch: expected %s, got %s\n' \
|
||||
"${ARCHIVE_SHA256}" "${actual_sha256}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if gh release view "${RELEASE_TAG}" --repo "${REPOSITORY}" >/dev/null 2>&1; then
|
||||
printf 'Release already exists: %s\n' "${RELEASE_TAG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
temporary_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "${temporary_dir}"' EXIT
|
||||
publish_archive="${temporary_dir}/${ASSET_NAME}"
|
||||
cp "${SOURCE_ARCHIVE}" "${publish_archive}"
|
||||
|
||||
gh release create "${RELEASE_TAG}" --repo "${REPOSITORY}" --title "FatFs R0.16" \
|
||||
--notes "Locked FatFs R0.16 source archive." "${publish_archive}"
|
||||
gh release download "$RELEASE_TAG" --repo "$REPOSITORY" --pattern "$ASSET_NAME" \
|
||||
--dir "${temporary_dir}/download"
|
||||
|
||||
published_sha256="$(sha256sum "${temporary_dir}/download/${ASSET_NAME}" | awk '{print $1}')"
|
||||
if [[ "${published_sha256}" != "${ARCHIVE_SHA256}" ]]; then
|
||||
printf 'Published FatFs archive checksum mismatch: expected %s, got %s\n' \
|
||||
"${ARCHIVE_SHA256}" "${published_sha256}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'Published https://github.com/%s/releases/download/%s/%s\n' \
|
||||
"${REPOSITORY}" "${RELEASE_TAG}" "${ASSET_NAME}"
|
||||
+18
-46
@@ -19,29 +19,14 @@ RTL_LINT_VALUES = ("SIMU=VERILATOR", "HAVE_SVA=YES", "rtl-lint", "check-rtl-lint
|
||||
|
||||
|
||||
PR_COMMANDS = (
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", RTL_LINT_VALUES),
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", ("firmware",)),
|
||||
("configs/ci/hazard3-rv32im-ihp130-shell.mk", ("firmware",)),
|
||||
("configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk", ("firmware",)),
|
||||
("configs/ci/ihp130.mk", RTL_LINT_VALUES),
|
||||
("configs/ci/ihp130.mk", ("firmware",)),
|
||||
("configs/ci/ihp130-shell.mk", ("firmware",)),
|
||||
("configs/ci/ihp130.mk", ("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim")),
|
||||
("configs/ci/ihp130.mk", ("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm")),
|
||||
("configs/ci/ihp130.mk", ("SYNTH=YOSYS", "synth")),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
(
|
||||
"configs/ci/mdd-rv32im-ihp130.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
|
||||
),
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", ("SYNTH=YOSYS", "synth")),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
"configs/ci/ihp130.mk",
|
||||
(
|
||||
"SIMU=IVERILOG",
|
||||
"SIM_FIRMWARE_NAME=retrosoc_asm",
|
||||
@@ -50,42 +35,29 @@ PR_COMMANDS = (
|
||||
"netsim",
|
||||
),
|
||||
),
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", ("STA=OPENSTA", "sta")),
|
||||
("configs/ci/ihp130.mk", ("STA=OPENSTA", "sta")),
|
||||
)
|
||||
SMOKE_COMMANDS = (
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", RTL_LINT_VALUES),
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", ("firmware",)),
|
||||
("configs/ci/ihp130.mk", RTL_LINT_VALUES),
|
||||
("configs/ci/ihp130.mk", ("firmware",)),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
"configs/ci/ihp130.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "comp"),
|
||||
),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
"configs/ci/ihp130.mk",
|
||||
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
|
||||
),
|
||||
)
|
||||
NIGHTLY_COMMANDS = PR_COMMANDS + (
|
||||
(
|
||||
"configs/nightly/picorv32-rv32im-ihp130.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
(
|
||||
"configs/nightly/picorv32-rv32im-ihp130.mk",
|
||||
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
|
||||
),
|
||||
)
|
||||
PR_PROFILES = (
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
"configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk",
|
||||
"configs/ci/mdd-rv32im-ihp130.mk",
|
||||
)
|
||||
NIGHTLY_COMMANDS = PR_COMMANDS
|
||||
PR_PROFILES = ("configs/ci/ihp130.mk",)
|
||||
SMOKE_PROFILES: tuple[str, ...] = ()
|
||||
NIGHTLY_PROFILES = PR_PROFILES + ("configs/nightly/picorv32-rv32im-ihp130.mk",)
|
||||
NIGHTLY_PROFILES = PR_PROFILES
|
||||
|
||||
PDK_PR_PROFILES = {
|
||||
"GF180": "configs/ci/hazard3-rv32im-gf180.mk",
|
||||
"IHP130": "configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
"SKY130": "configs/ci/hazard3-rv32im-sky130.mk",
|
||||
"GF180": "configs/ci/gf180.mk",
|
||||
"IHP130": "configs/ci/ihp130.mk",
|
||||
"SKY130": "configs/ci/sky130.mk",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ def main() -> int:
|
||||
with tempfile.TemporaryDirectory(prefix="retrosoc-c-tests-") as temporary_directory:
|
||||
temporary_root = Path(temporary_directory)
|
||||
memory_map_root = temporary_root / "memory_map"
|
||||
user_extensions_root = temporary_root / "user_extensions"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
@@ -51,6 +52,17 @@ def main() -> int:
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(root / "rtl/mini/integration/generate_user_extensions.py"),
|
||||
"--map",
|
||||
str(root / "rtl/mini/integration/user_extensions.json"),
|
||||
"--output-dir",
|
||||
str(user_extensions_root),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
executable = temporary_root / "runtime_tests"
|
||||
command = [
|
||||
compiler,
|
||||
@@ -59,9 +71,12 @@ def main() -> int:
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-fno-builtin",
|
||||
"-DRS_SOC_MGMT_CORE_HAZARD3",
|
||||
"-I",
|
||||
str(memory_map_root / "include"),
|
||||
"-I",
|
||||
str(user_extensions_root / "include"),
|
||||
"-I",
|
||||
str(root / "crt/include"),
|
||||
"-I",
|
||||
str(root / "app/media/include"),
|
||||
|
||||
Reference in new issue
Block a user