mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: refactor tests and update configurations for OpenC906 migration
- Adjusted slot assignments in to reflect new peripheral mappings. - Updated to validate new OpenC906 configurations, including generator and profile checks. - Modified to reference the new Std-series VexiiRiscv generator. - Changed cache maintenance instructions in to align with C906 specifications. - Revised assertions in to account for internal unit removals. - Updated to reflect changes in peripheral interface counts and policies. - Added new test file to ensure preservation of the frozen HP configuration in the Std-series generator.
This commit is contained in:
133 files changed
+8797
-2420
No files matched your search
+3
-2
@@ -126,8 +126,9 @@ SRAM CoreMark quick report into `meta/coremark.json`; it requires one valid
|
||||
than replace, the common `SIM_TEST_PASS` simulation verdict.
|
||||
|
||||
`generate_vexiiriscv.py` verifies the locked VexiiRiscv revision, rejects local
|
||||
source changes before and after generation, and generates the fixed HP core
|
||||
below `build/`; generated RTL is never tracked.
|
||||
source changes before and after generation, and generates the fixed Std-series
|
||||
core (preserved from the retired Mini HP configuration) below `build/`; generated
|
||||
RTL is never tracked.
|
||||
`setup_hp_linux.py` installs the locked OpenSBI, Linux, and Buildroot revisions
|
||||
and can resume a checkout left without `HEAD` by an interrupted fetch.
|
||||
`build_hp_linux.py` builds the RV64 `lp64d` userspace/OpenSBI image set with the repo-owned
|
||||
|
||||
@@ -25,7 +25,7 @@ def build(args: argparse.Namespace) -> None:
|
||||
subprocess.run(
|
||||
[
|
||||
compiler,
|
||||
"-march=rv64imafdc_zicbom_zicsr_zifencei",
|
||||
"-march=rv64imafdc_zicsr_zifencei",
|
||||
"-mabi=lp64d",
|
||||
"-nostdlib",
|
||||
"-nostartfiles",
|
||||
|
||||
@@ -250,7 +250,7 @@ def build(args: argparse.Namespace) -> None:
|
||||
f"PLATFORM_DIR={external / 'opensbi'}",
|
||||
"PLATFORM_RISCV_XLEN=64",
|
||||
"PLATFORM_RISCV_ABI=lp64d",
|
||||
"PLATFORM_RISCV_ISA=rv64imafdc_zicbom_zicsr_zifencei",
|
||||
"PLATFORM_RISCV_ISA=rv64imafdc_zicsr_zifencei",
|
||||
"FW_TEXT_START=0x38000000",
|
||||
"FW_JUMP=y",
|
||||
"FW_JUMP_ADDR=0x38400000",
|
||||
|
||||
@@ -22,7 +22,7 @@ def build(args: argparse.Namespace) -> None:
|
||||
objcopy = f"{args.cross}objcopy"
|
||||
command = [
|
||||
compiler,
|
||||
"-march=rv64imafdc_zicbom_zicsr_zifencei",
|
||||
"-march=rv64imafdc_zicsr_zifencei",
|
||||
"-mabi=lp64d",
|
||||
"-nostdlib",
|
||||
"-nostartfiles",
|
||||
|
||||
@@ -21,6 +21,10 @@ SELF_OWNED_RTL_ROOTS = {
|
||||
("rtl", "tech"),
|
||||
("tests", "rtl"),
|
||||
}
|
||||
# Vendored upstream sources carried with a reviewed patch (e.g. the OpenC906
|
||||
# hart-ID override) keep upstream formatting so they stay diffable against
|
||||
# the locked revision.
|
||||
VENDORED_RTL_DIRS = ("ip_overrides",)
|
||||
|
||||
|
||||
def tracked_files(root: Path) -> list[Path]:
|
||||
@@ -41,7 +45,9 @@ def format_files(paths: Iterable[Path], kind: str) -> list[Path]:
|
||||
return sorted(
|
||||
path
|
||||
for path in paths
|
||||
if path.suffix in RTL_SUFFIXES and tuple(path.parts[:2]) in SELF_OWNED_RTL_ROOTS
|
||||
if path.suffix in RTL_SUFFIXES
|
||||
and tuple(path.parts[:2]) in SELF_OWNED_RTL_ROOTS
|
||||
and not any(part in VENDORED_RTL_DIRS for part in path.parts)
|
||||
)
|
||||
raise ValueError(f"unknown format kind: {kind}")
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Emit the Mini HP OpenC906 filelist from the locked vendored source.
|
||||
|
||||
The OpenC906 repository ships pre-generated Verilog below
|
||||
``C906_RTL_FACTORY/gen_rtl`` together with upstream filelists that use a
|
||||
``${CODE_BASE_PATH}`` placeholder and mix compilation-unit macro headers with
|
||||
sources. This script resolves the placeholder to the locked checkout and
|
||||
substitutes the reviewed retroSoC overrides from ``rtl/mini/ip_overrides/``
|
||||
for their vendored counterparts:
|
||||
|
||||
- ``aq_sysio_kid.v``: upstream hardwires mhartid to 0; the Mini LP/HP
|
||||
contract requires the HP core to report hart 1.
|
||||
- ``sysmap.h``: the upstream default region table marks the Mini peripheral
|
||||
window cacheable/bufferable; the override maps the Mini address map with
|
||||
the MMIO window (including the core-internal CLINT/PLIC window) as
|
||||
strong-order non-cacheable, as the OpenC906 user manual requires.
|
||||
|
||||
All sources are concatenated into a single compilation unit
|
||||
(``openc906_combined.v``) because gen_rtl relies on header macros being
|
||||
visible in every source; one file preserves that semantics for tools with
|
||||
per-file compilation units (slang/Yosys) and is equivalent for
|
||||
Verilator/Icarus/VCS. The vendored checkout itself is never modified.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
GENERATED_MODULE = "openC906"
|
||||
UPSTREAM_FILELISTS = (
|
||||
"C906_RTL_FACTORY/gen_rtl/filelists/C906_asic_rtl.fl",
|
||||
"C906_RTL_FACTORY/gen_rtl/filelists/tdt_dmi_top_rtl.fl",
|
||||
)
|
||||
# vendored relpath -> (override relpath below rtl/mini/ip_overrides/, sha256 of
|
||||
# the vendored file at the locked revision). The sha256 pins force a review of
|
||||
# the override whenever the locked OpenC906 revision moves.
|
||||
OVERRIDE_DIR = Path("rtl/mini/ip_overrides")
|
||||
OVERRIDES = {
|
||||
"C906_RTL_FACTORY/gen_rtl/cpu/rtl/aq_sysio_kid.v": (
|
||||
"aq_sysio_kid.v",
|
||||
"afb4d8da4c9fb01edf9286c69111c9799ccf0cc66c339dadad1705efdd35dd8c",
|
||||
),
|
||||
"C906_RTL_FACTORY/gen_rtl/mmu/rtl/sysmap.h": (
|
||||
"sysmap.h",
|
||||
"0389089a42ef762768e57bbb4fdcbe6b95f33ab650b5bacc0de8122e0d8711d5",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def run(command: list[str], cwd: Path) -> str:
|
||||
result = subprocess.run(command, cwd=cwd, check=True, capture_output=True, text=True)
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as source:
|
||||
for chunk in iter(lambda: source.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def locked_revision(lock_path: Path) -> str:
|
||||
document: dict[str, Any] = json.loads(lock_path.read_text(encoding="utf-8"))
|
||||
source = document.get("sources", {}).get("openc906")
|
||||
if not isinstance(source, dict) or not isinstance(source.get("revision"), str):
|
||||
raise ValueError("dependency lock has no openc906 source revision")
|
||||
return source["revision"]
|
||||
|
||||
|
||||
def validate_locked_source(source: Path, expected: str) -> str:
|
||||
actual = run(["git", "rev-parse", "HEAD"], source)
|
||||
if actual != expected:
|
||||
raise ValueError(f"OpenC906 revision mismatch: expected {expected}, found {actual}")
|
||||
status = run(["git", "status", "--short"], source)
|
||||
if status:
|
||||
raise ValueError("OpenC906 source has local changes:\n" + status)
|
||||
return actual
|
||||
|
||||
|
||||
def collect_sources(root: Path, source: Path) -> tuple[list[Path], dict[str, str]]:
|
||||
"""Resolve upstream filelists to absolute source paths with overrides."""
|
||||
files: list[Path] = []
|
||||
used: dict[str, str] = {}
|
||||
for filelist in UPSTREAM_FILELISTS:
|
||||
for line in (source / filelist).read_text(encoding="utf-8").splitlines():
|
||||
entry = line.strip()
|
||||
if not entry or entry.startswith("#"):
|
||||
continue
|
||||
resolved = Path(entry.replace("${CODE_BASE_PATH}", str(source / "C906_RTL_FACTORY")))
|
||||
if not resolved.is_file():
|
||||
raise FileNotFoundError(f"upstream filelist entry not found: {resolved}")
|
||||
if resolved.suffix != ".h" and resolved.suffix != ".v":
|
||||
raise ValueError(f"unexpected upstream filelist entry kind: {resolved}")
|
||||
relative = resolved.relative_to(source).as_posix()
|
||||
if relative in OVERRIDES:
|
||||
override_name, expected_sha256 = OVERRIDES[relative]
|
||||
if sha256(resolved) != expected_sha256:
|
||||
raise ValueError(
|
||||
f"vendored {Path(relative).name} digest changed; re-review the "
|
||||
"override before updating OVERRIDES"
|
||||
)
|
||||
resolved = (root / OVERRIDE_DIR / override_name).resolve()
|
||||
if not resolved.is_file():
|
||||
raise FileNotFoundError(f"override not found: {resolved}")
|
||||
used[relative] = override_name
|
||||
files.append(resolved)
|
||||
missing = set(OVERRIDES) - set(used)
|
||||
if missing:
|
||||
raise ValueError(f"override target(s) not present in upstream filelists: {missing}")
|
||||
return files, used
|
||||
|
||||
|
||||
def generate(args: argparse.Namespace) -> None:
|
||||
root = args.root.resolve()
|
||||
source = args.source.resolve()
|
||||
output = args.output.resolve()
|
||||
expected = locked_revision(args.lock.resolve())
|
||||
actual = validate_locked_source(source, expected)
|
||||
|
||||
files, used = collect_sources(root, source)
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
combined = output / "openc906_combined.v"
|
||||
chunks = [
|
||||
"// retroSoC build-time concatenation of the locked OpenC906 RTL.\n",
|
||||
"// Do not edit; regenerate with `make openc906-prepare`.\n",
|
||||
]
|
||||
for path in files:
|
||||
chunks.append(f"\n// ---- begin: {path.name} ----\n")
|
||||
chunks.append(path.read_text(encoding="utf-8"))
|
||||
chunks.append("\n")
|
||||
combined.write_text("".join(chunks), encoding="utf-8")
|
||||
(output / "openc906.fl").write_text(str(combined) + "\n", encoding="utf-8")
|
||||
|
||||
manifest = {
|
||||
"schema_version": 1,
|
||||
"module": GENERATED_MODULE,
|
||||
"configuration": "openc906_default_rv64gc",
|
||||
"openc906_revision": actual,
|
||||
"source_status": [],
|
||||
"overrides": {
|
||||
target: {
|
||||
"override": str(OVERRIDE_DIR / override_name),
|
||||
"expected_upstream_sha256": OVERRIDES[target][1],
|
||||
}
|
||||
for target, override_name in sorted(used.items())
|
||||
},
|
||||
"file_count": len(files),
|
||||
}
|
||||
args.manifest.resolve().parent.mkdir(parents=True, exist_ok=True)
|
||||
args.manifest.resolve().write_text(
|
||||
json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--root", type=Path, required=True)
|
||||
parser.add_argument("--source", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--manifest", type=Path, required=True)
|
||||
parser.add_argument("--lock", type=Path, required=True)
|
||||
generate(parser.parse_args())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate the locked VexiiRiscv HP core below the selected build variant."""
|
||||
"""Generate the locked VexiiRiscv Std-series core below the selected build variant.
|
||||
|
||||
The generator is a Std-series asset preserved from the retired Mini HP
|
||||
configuration; Mini no longer consumes it.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -12,8 +16,8 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
GENERATOR_CLASS = "vexiiriscv.GenerateRetroSocHp"
|
||||
GENERATED_MODULE = "vexii_riscv_hp_generated"
|
||||
GENERATOR_CLASS = "vexiiriscv.GenerateRetroSocStd"
|
||||
GENERATED_MODULE = "vexiiriscv_std_generated"
|
||||
|
||||
|
||||
def run(command: list[str], cwd: Path) -> str:
|
||||
@@ -86,7 +90,7 @@ def generate(args: argparse.Namespace) -> None:
|
||||
environment["COURSIER_CACHE"] = str(sbt_cache / "coursier")
|
||||
subprocess.run(command, cwd=source, check=True, env=environment)
|
||||
|
||||
generated = output / "vexii_riscv_hp_generated.v"
|
||||
generated = output / "vexiiriscv_std_generated.v"
|
||||
if not generated.is_file():
|
||||
raise FileNotFoundError(f"VexiiRiscv generator did not create {generated}")
|
||||
validate_locked_source(source, expected)
|
||||
@@ -95,6 +99,7 @@ def generate(args: argparse.Namespace) -> None:
|
||||
manifest = {
|
||||
"schema_version": 1,
|
||||
"module": GENERATED_MODULE,
|
||||
"product": "std",
|
||||
"configuration": "rv64imafdc_zicbom_max",
|
||||
"xlen": 64,
|
||||
"physical_address_width": 32,
|
||||
@@ -102,7 +107,7 @@ def generate(args: argparse.Namespace) -> None:
|
||||
"vexiiriscv_revision": actual,
|
||||
"source_status": [],
|
||||
"submodules": submodules,
|
||||
"generator": str((scala_dir / "GenerateRetroSocHp.scala").relative_to(root)),
|
||||
"generator": str((scala_dir / "GenerateRetroSocStd.scala").relative_to(root)),
|
||||
"files": {generated.name: sha256(generated)},
|
||||
}
|
||||
args.manifest.resolve().parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -287,6 +287,14 @@ static void rs_{prefix}_cache_clean(const void *pointer, uint32_t bytes) {{
|
||||
uintptr_t cursor = (uintptr_t)pointer & ~(uintptr_t)UINT32_C(63);
|
||||
uintptr_t end = ((uintptr_t)pointer + bytes + UINT32_C(63)) & ~(uintptr_t)UINT32_C(63);
|
||||
while (cursor < end) {{ __asm__ volatile("cbo.clean 0(%0)" :: "r"(cursor) : "memory"); cursor += 64U; }}
|
||||
#elif defined(__riscv)
|
||||
/* OpenC906 (T-Head C906): custom-0 dcache.cva, 0x0250000b | rs1<<15 */
|
||||
uintptr_t cursor = (uintptr_t)pointer & ~(uintptr_t)UINT32_C(63);
|
||||
uintptr_t end = ((uintptr_t)pointer + bytes + UINT32_C(63)) & ~(uintptr_t)UINT32_C(63);
|
||||
while (cursor < end) {{
|
||||
__asm__ volatile(".insn r 0x0b, 0x0, 0x01, x0, %0, x5" :: "r"(cursor) : "memory");
|
||||
cursor += 64U;
|
||||
}}
|
||||
#else
|
||||
(void)pointer; (void)bytes;
|
||||
#endif
|
||||
@@ -297,6 +305,14 @@ static void rs_{prefix}_cache_invalidate(const void *pointer, uint32_t bytes) {{
|
||||
uintptr_t cursor = (uintptr_t)pointer & ~(uintptr_t)UINT32_C(63);
|
||||
uintptr_t end = ((uintptr_t)pointer + bytes + UINT32_C(63)) & ~(uintptr_t)UINT32_C(63);
|
||||
while (cursor < end) {{ __asm__ volatile("cbo.inval 0(%0)" :: "r"(cursor) : "memory"); cursor += 64U; }}
|
||||
#elif defined(__riscv)
|
||||
/* OpenC906 (T-Head C906): custom-0 dcache.iva, 0x0260000b | rs1<<15 */
|
||||
uintptr_t cursor = (uintptr_t)pointer & ~(uintptr_t)UINT32_C(63);
|
||||
uintptr_t end = ((uintptr_t)pointer + bytes + UINT32_C(63)) & ~(uintptr_t)UINT32_C(63);
|
||||
while (cursor < end) {{
|
||||
__asm__ volatile(".insn r 0x0b, 0x0, 0x01, x0, %0, x6" :: "r"(cursor) : "memory");
|
||||
cursor += 64U;
|
||||
}}
|
||||
#else
|
||||
(void)pointer; (void)bytes;
|
||||
#endif
|
||||
|
||||
@@ -111,7 +111,7 @@ def build_variants(timestamp: str, log_dir: Path) -> dict[str, Path]:
|
||||
|
||||
|
||||
def qualification_configuration(variants: dict[str, Path]) -> dict[str, object]:
|
||||
selected = ("MINI_MODE", "APP", "SIMU", "HP_CONFIG", "EXT_CLK_HZ")
|
||||
selected = ("MINI_MODE", "APP", "SIMU", "EXT_CLK_HZ")
|
||||
configurations: dict[str, dict[str, str]] = {}
|
||||
for workload, variant in variants.items():
|
||||
manifest = json.loads((variant / "meta/manifest.json").read_text(encoding="utf-8"))
|
||||
@@ -128,7 +128,6 @@ def qualification_configuration(variants: dict[str, Path]) -> dict[str, object]:
|
||||
"MINI_MODE": "PRODUCT",
|
||||
"APP": "hp_boot",
|
||||
"SIMU": "VERILATOR",
|
||||
"HP_CONFIG": "rv64imafdc_zicbom_max",
|
||||
"EXT_CLK_HZ": "72000000",
|
||||
}
|
||||
if configuration != expected:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install the locked OpenC906 source used by Mini product profiles."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from dependency_lock import source
|
||||
from setup_helpers import ensure_git_repo
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--update", action="store_true")
|
||||
args = parser.parse_args()
|
||||
dependency = source("openc906")
|
||||
destination = ROOT / dependency["destination"]
|
||||
ensure_git_repo(
|
||||
dependency["url"],
|
||||
destination,
|
||||
dependency["revision"],
|
||||
recursive=dependency.get("recursive", False),
|
||||
update=args.update,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+6
-4
@@ -8,9 +8,11 @@ import vexiiriscv.misc.EmbeddedRiscvJtag
|
||||
|
||||
import java.nio.file.{Files, Paths}
|
||||
|
||||
/** Generates the fixed retroSoC RV64 application core. */
|
||||
object GenerateRetroSocHp extends App {
|
||||
require(args.length == 1, "usage: GenerateRetroSocHp <output-directory>")
|
||||
/** Generates the fixed retroSoC Std-series RV64 application core configuration
|
||||
* (preserved from the retired Mini HP configuration).
|
||||
*/
|
||||
object GenerateRetroSocStd extends App {
|
||||
require(args.length == 1, "usage: GenerateRetroSocStd <output-directory>")
|
||||
|
||||
val output = Paths.get(args(0)).toAbsolutePath.normalize
|
||||
Files.createDirectories(output)
|
||||
@@ -120,6 +122,6 @@ object GenerateRetroSocHp extends App {
|
||||
)
|
||||
)
|
||||
)
|
||||
VexiiRiscv(plugins).setDefinitionName("vexii_riscv_hp_generated")
|
||||
VexiiRiscv(plugins).setDefinitionName("vexiiriscv_std_generated")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user