feat: introduce RV64 support and related tooling for HP workloads

- Added build_hp_rtthread.py for building the RT-Thread kernel with RV64 support.
- Updated build_hp_smoke.py to target RV64 architecture and modified output filenames.
- Modified generate_vexiiriscv.py to reflect RV64 configuration and memory management.
- Created hp_tools.py for shared utilities related to RV64 builds.
- Enhanced package_hp_boot.py to package RV64 workloads and updated versioning.
- Implemented run_hp_sim.py for executing and validating HP workloads with specific markers.
- Developed setup_hp_rtthread.py for installing RT-Thread source and environment setup.
- Updated GenerateRetroSocHp.scala to generate RV64 application cores.
- Enhanced tests for HP boot bundles, platform specifications, and tool utilities to accommodate RV64 changes.
- Adjusted test cases to validate new workload types and ensure compatibility with RV64 architecture.
This commit is contained in:
maksyuki committed 2026-09-26 15:47:26 +08:00
1 parent 75ed04e7ef
commit 0e36b6a82f
81 files changed
+1785 -319

No files matched your search

+9 -2
View File
@@ -47,11 +47,18 @@ than replace, the common `SIM_TEST_PASS` simulation verdict.
the fixed HP core 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 RV32 `ilp32d` image set with the repo-owned
external OpenSBI platform. `package_hp_boot.py` creates the v1 LP/HP flash
`build_hp_linux.py` builds the RV64 `lp64d` userspace/OpenSBI image set with the repo-owned
external OpenSBI platform. `package_hp_boot.py` creates the V2 typed LP/HP flash
bundle and its SHA-256/CRC manifest. `check_lp_hp_performance.py` applies the
measured 2.5x CoreMark/MHz gate.
`setup_hp_rtthread.py` installs the locked kernel, RV64 bare-metal compiler and
isolated SCons environment. `build_hp_rtthread.py` stages only the repository BSP
under the variant and records the source/compiler/configuration inputs.
`hp_tools.py` checks source revisions and RV64 ELF class. `run_hp_sim.py` keeps
Linux, smoke and RT-Thread logs/verdicts separate and checks every required
workload marker together with a successful process exit.
`run_debug_session.py` is the local Hazard3 debug acceptance driver. It starts
the Verilator remote-bitbang endpoint, the lock-pinned OpenOCD binary, and
RISC-V GDB, then records their logs and a structured result. Invoke it through
+94 -14
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Build the pinned RV32 HP Buildroot, Linux, DTB, and OpenSBI images."""
"""Build pinned RV64 Linux images with a small, static acceptance initramfs."""
from __future__ import annotations
@@ -11,30 +11,45 @@ import shutil
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import require_revision, require_rv64_elf
except ModuleNotFoundError:
from hp_tools import require_revision, require_rv64_elf
LAYOUT = {
"fw_jump.bin": (0x38000000, 512 * 1024),
"retrosoc_hp.dtb": (0x38080000, 64 * 1024),
"Image": (0x38400000, 12 * 1024 * 1024),
"rootfs.cpio.gz": (0x39000000, 8 * 1024 * 1024),
"rootfs.cpio": (0x39000000, 8 * 1024 * 1024),
}
REQUIRED_LINUX_CONFIG = (
"CONFIG_ARCH_RV64I",
"CONFIG_64BIT",
"CONFIG_MMU",
"CONFIG_OF_RESERVED_MEM",
"CONFIG_BINFMT_ELF",
"CONFIG_BINFMT_SCRIPT",
"CONFIG_PRINTK",
"CONFIG_TTY",
"CONFIG_HVC_RISCV_SBI",
"CONFIG_SERIAL_EARLYCON_RISCV_SBI",
"CONFIG_PROC_FS",
"CONFIG_SYSFS",
"CONFIG_SHMEM",
"CONFIG_TMPFS",
"CONFIG_DEVTMPFS",
"CONFIG_DEVMEM",
)
def command(arguments: list[str], cwd: Path) -> None:
def command(arguments: list[str], cwd: Path, extra_env: dict[str, str] | None = None) -> None:
environment = dict(os.environ)
environment.pop("CONFIG", None)
environment.pop("MAKEFLAGS", None)
environment.pop("MAKEOVERRIDES", None)
environment.pop("MFLAGS", None)
environment.update(extra_env or {})
subprocess.run(arguments, cwd=cwd, check=True, env=environment)
@@ -60,12 +75,44 @@ def source_revision(path: Path) -> str:
def find_toolchain(buildroot_output: Path) -> str:
matches = sorted((buildroot_output / "host/bin").glob("riscv32*-linux-*-gcc"))
matches = sorted((buildroot_output / "host/bin").glob("riscv64*-linux-*-gcc"))
if len(matches) != 1:
raise RuntimeError(f"expected one RV32 Linux GCC in {buildroot_output / 'host/bin'}")
raise RuntimeError(f"expected one RV64 Linux GCC in {buildroot_output / 'host/bin'}")
return str(matches[0])[: -len("gcc")]
def minimal_busybox(buildroot: Path, output: Path, external: Path, jobs: int) -> str:
"""Expand an allowlist using BusyBox's own allnoconfig, not default-y oldconfig."""
make = ["make", f"O={output}", f"BR2_EXTERNAL={external}", f"-j{jobs}"]
command([*make, "busybox-configure"], buildroot)
sources = [path for path in (output / "build").glob("busybox-*")
if (path / "scripts/kconfig/conf").is_file()]
if len(sources) != 1:
raise RuntimeError("expected one configured locked BusyBox source")
source = sources[0]
config_dir = output.parent / "busybox-config"
(config_dir / "include").mkdir(parents=True, exist_ok=True)
command([str(source / "scripts/kconfig/conf"), "-n", str(source / "Config.in")], config_dir,
{"srctree": str(source), "KCONFIG_NOTIMESTAMP": "1",
"KCONFIG_ALLCONFIG": str(external / "busybox/retrosoc_hp.config")})
# This BusyBox conf implementation resets booleans even when ALLCONFIG
# specified y. Overlay our explicit choices after its all-no expansion;
# Buildroot's ordinary oldconfig then resolves the real dependencies.
selected = dict(line.split("=", 1) for line in
(external / "busybox/retrosoc_hp.config").read_text().splitlines()
if line.startswith("CONFIG_") and "=" in line)
config = config_dir / ".config"
lines = []
for line in config.read_text().splitlines():
key = line[2:].split(" ", 1)[0] if line.startswith("# CONFIG_") else line.split("=", 1)[0]
lines.append(f"{key}={selected.pop(key)}" if key in selected else line)
lines.extend(f"{key}={value}" for key, value in selected.items())
config.write_text("\n".join(lines) + "\n", encoding="utf-8")
config_arg = f"BUSYBOX_CONFIG_FILE={config_dir / '.config'}"
command([*make, config_arg, "busybox-reconfigure"], buildroot)
return config_arg
def validate_linux_config(config: Path) -> None:
values: dict[str, str] = {}
for line in config.read_text(encoding="utf-8").splitlines():
@@ -94,6 +141,9 @@ def build(args: argparse.Namespace) -> None:
buildroot = require_source(args.buildroot, "Buildroot")
linux = require_source(args.linux, "Linux")
opensbi = require_source(args.opensbi, "OpenSBI")
for name, path in (("buildroot_hp", buildroot), ("linux_hp", linux), ("opensbi_hp", opensbi)):
if path != require_revision(root, name).resolve():
raise ValueError(f"{name} must use its locked source directory")
external = root / "app/ports/linux"
buildroot_output = output / "buildroot"
@@ -101,7 +151,16 @@ def build(args: argparse.Namespace) -> None:
["make", f"O={buildroot_output}", f"BR2_EXTERNAL={external}", "retrosoc_hp_defconfig"],
buildroot,
)
command(["make", f"O={buildroot_output}", f"BR2_EXTERNAL={external}", f"-j{args.jobs}"], buildroot)
busybox_config = minimal_busybox(buildroot, buildroot_output, external, args.jobs)
command(["make", f"O={buildroot_output}", f"BR2_EXTERNAL={external}",
busybox_config, f"-j{args.jobs}"], buildroot)
busybox_sources = sorted((buildroot_output / "build").glob("busybox-*/.config"))
if len(busybox_sources) != 1:
raise RuntimeError("missing effective BusyBox configuration")
busybox_effective = busybox_sources[0].read_text().splitlines()
for symbol in ("STATIC", "BUSYBOX", "ASH", "MOUNT", "TEST", "ECHO", "CAT", "TRUE"):
if f"CONFIG_{symbol}=y" not in busybox_effective:
raise RuntimeError(f"HP BusyBox requires CONFIG_{symbol}=y")
cross_compile = find_toolchain(buildroot_output)
linux_output = output / "linux"
@@ -133,10 +192,28 @@ def build(args: argparse.Namespace) -> None:
image_dir = output / "images"
image_dir.mkdir(parents=True, exist_ok=True)
rootfs_source = buildroot_output / "images/rootfs.cpio.gz"
if not rootfs_source.is_file():
raise FileNotFoundError(f"HP Linux build output is missing: {rootfs_source}")
initrd_end = LAYOUT["rootfs.cpio.gz"][0] + rootfs_source.stat().st_size
require_rv64_elf(linux_output / "vmlinux")
busybox = buildroot_output / "target/bin/busybox"
require_rv64_elf(busybox)
if "INTERP" in subprocess.check_output([cross_compile + "readelf", "-l", str(busybox)], text=True):
raise ValueError("HP acceptance BusyBox must be statically linked")
helper = output / "hp-ready"
command([cross_compile + "gcc", "-Os", "-static", "-Wall", "-Wextra", "-Werror",
"-o", str(helper), str(external / "hp_ready.c")], root)
require_rv64_elf(helper)
archive_spec = output / "initramfs.list"
entries = [f"dir /{name} 755 0 0" for name in ("bin", "dev", "proc", "sys", "tmp")]
entries += [f"file /bin/busybox {busybox} 755 0 0",
f"file /bin/hp-ready {helper} 755 0 0", f"file /init {external / 'init'} 755 0 0",
"nod /dev/console 600 0 0 c 5 1", "nod /dev/mem 600 0 0 c 1 1"]
entries += [f"slink /bin/{name} busybox 777 0 0" for name in
("sh", "mount", "mkdir", "echo", "test", "cat", "sleep")]
archive_spec.write_text("\n".join(entries) + "\n", encoding="utf-8")
rootfs_source = image_dir / "rootfs.cpio"
with rootfs_source.open("wb") as archive:
subprocess.run([str(linux_output / "usr/gen_init_cpio"), "-t", "0", str(archive_spec)],
stdout=archive, check=True)
initrd_end = LAYOUT["rootfs.cpio"][0] + rootfs_source.stat().st_size
command(
[
"dtc",
@@ -171,9 +248,9 @@ def build(args: argparse.Namespace) -> None:
f"CROSS_COMPILE={cross_compile}",
"PLATFORM=retrosoc_hp",
f"PLATFORM_DIR={external / 'opensbi'}",
"PLATFORM_RISCV_XLEN=32",
"PLATFORM_RISCV_ABI=ilp32d",
"PLATFORM_RISCV_ISA=rv32imafdc_zicbom_zicsr_zifencei",
"PLATFORM_RISCV_XLEN=64",
"PLATFORM_RISCV_ABI=lp64d",
"PLATFORM_RISCV_ISA=rv64imafdc_zicbom_zicsr_zifencei",
"FW_TEXT_START=0x38000000",
"FW_JUMP=y",
"FW_JUMP_ADDR=0x38400000",
@@ -186,15 +263,18 @@ def build(args: argparse.Namespace) -> None:
copies = {
opensbi_output / "platform/retrosoc_hp/firmware/fw_jump.bin": image_dir / "fw_jump.bin",
linux_output / "arch/riscv/boot/Image": image_dir / "Image",
rootfs_source: image_dir / "rootfs.cpio.gz",
}
for source, destination in copies.items():
if not source.is_file():
raise FileNotFoundError(f"HP Linux build output is missing: {source}")
shutil.copy2(source, destination)
require_rv64_elf(opensbi_output / "platform/retrosoc_hp/firmware/fw_jump.elf")
manifest: dict[str, object] = {
"schema_version": 1,
"xlen": 64,
"abi": "lp64d",
"initramfs": "minimal-static-uncompressed",
"boot_flow": "opensbi-fw_jump",
"hart_id": 1,
"sources": {
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Build the repository BSP against the unmodified, locked RT-Thread kernel."""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import re
import shutil
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import cross_prefix, require_revision, require_rv64_elf
except ModuleNotFoundError:
from hp_tools import cross_prefix, require_revision, require_rv64_elf
def build(root: Path, output: Path, jobs: int) -> None:
source = require_revision(root, "rtthread_hp")
bsp = output / "bsp"
bsp.mkdir(parents=True, exist_ok=True)
for path in (root / "app/ports/rtthread").iterdir():
if path.is_file():
shutil.copy2(path, bsp / path.name)
environment = dict(os.environ)
for key in ("CONFIG", "MAKEFLAGS", "MAKEOVERRIDES", "MFLAGS"):
environment.pop(key, None)
environment.update(RTT_ROOT=str(source), RTT_EXEC_PATH=str(Path(cross_prefix(root)).parent),
RETROSOC_ROOT=str(root))
expected = re.search(r"^scons==([\d.]+)", (root / "requirements/rtthread.txt").read_text(), re.M)
actual = subprocess.check_output([str(root / ".cache/retrosoc/rtthread-venv/bin/python"),
"-c", "import SCons; print(SCons.__version__)"], text=True).strip()
if expected is None or actual != expected[1]:
raise ValueError(f"RT-Thread SCons version does not match requirements: {actual}")
subprocess.run([str(root / ".cache/retrosoc/rtthread-venv/bin/scons"), f"-j{jobs}"],
cwd=bsp, env=environment, check=True)
require_rv64_elf(bsp / "rtthread.elf")
images = output / "images"
images.mkdir(parents=True, exist_ok=True)
for name in ("rtthread.elf", "rtthread.bin", "rtthread.map"):
shutil.copy2(bsp / name, images / name)
revision = subprocess.check_output(["git", "-C", str(source), "rev-parse", "HEAD"],
text=True).strip()
manifest = {"schema_version": 1, "xlen": 64, "abi": "lp64d", "hart_id": 1,
"rtthread_revision": revision,
"scons_version": actual,
"compiler": subprocess.check_output([cross_prefix(root) + "gcc", "--version"],
text=True).splitlines()[0],
"sha256": hashlib.sha256((images / "rtthread.bin").read_bytes()).hexdigest()}
manifest["inputs"] = {str(path.relative_to(root)): hashlib.sha256(path.read_bytes()).hexdigest()
for path in sorted((root / "app/ports/rtthread").iterdir()) if path.is_file()}
manifest["inputs"]["requirements/rtthread.txt"] = hashlib.sha256(
(root / "requirements/rtthread.txt").read_bytes()).hexdigest()
(images / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--jobs", type=int, default=1)
args = parser.parse_args()
build(args.root.resolve(), args.output.resolve(), args.jobs)
if __name__ == "__main__":
main()
+10 -7
View File
@@ -7,6 +7,11 @@ import argparse
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import require_rv64_elf
except ModuleNotFoundError:
from hp_tools import require_rv64_elf
def build(args: argparse.Namespace) -> None:
output = args.output.resolve()
@@ -18,8 +23,8 @@ def build(args: argparse.Namespace) -> None:
subprocess.run(
[
compiler,
"-march=rv32imafdc_zicbom_zicsr_zifencei",
"-mabi=ilp32d",
"-march=rv64imafdc_zicbom_zicsr_zifencei",
"-mabi=lp64d",
"-nostdlib",
"-nostartfiles",
"-Wl,--build-id=none",
@@ -30,13 +35,11 @@ def build(args: argparse.Namespace) -> None:
],
check=True,
)
require_rv64_elf(elf)
subprocess.run(
[objcopy, "-O", "binary", str(elf), str(images / "fw_jump.bin")],
[objcopy, "-O", "binary", str(elf), str(images / "hp_smoke.bin")],
check=True,
)
(images / "retrosoc_hp.dtb").write_bytes(b"SMOK")
(images / "Image").write_bytes(b"SMOK")
(images / "rootfs.cpio.gz").write_bytes(b"SMOK")
def main() -> None:
@@ -44,7 +47,7 @@ def main() -> None:
parser.add_argument("--source", type=Path, required=True)
parser.add_argument("--linker", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--cross", default="riscv32-unknown-elf-")
parser.add_argument("--cross", default="riscv64-unknown-elf-")
build(parser.parse_args())
+4 -1
View File
@@ -86,7 +86,10 @@ def generate(args: argparse.Namespace) -> None:
manifest = {
"schema_version": 1,
"module": GENERATED_MODULE,
"configuration": "rv32imafdc_zicbom_max",
"configuration": "rv64imafdc_zicbom_max",
"xlen": 64,
"physical_address_width": 32,
"mmu": "sv39",
"vexiiriscv_revision": actual,
"source_status": git_status(source),
"submodules": submodules,
+46
View File
@@ -0,0 +1,46 @@
"""Shared locked RV64 build helpers for HP payloads."""
from __future__ import annotations
import argparse
import struct
import subprocess
from pathlib import Path
try:
from scripts.dependency_lock import load_lock
except ModuleNotFoundError:
from dependency_lock import load_lock
def cross_prefix(root: Path) -> str:
spec = load_lock(root / "dependencies/dependencies.lock.json")["toolchains"]["ubuntu-22.04"][
"riscv_gnu_hp"
]
return str(root / ".cache/retrosoc/development/toolchains" /
f"riscv_gnu_hp-{spec['version']}" / spec["path"] / "riscv64-unknown-elf-")
def require_rv64_elf(path: Path) -> None:
header = path.read_bytes()[:64]
if (len(header) < 64 or header[:6] != b"\x7fELF\x02\x01" or
struct.unpack_from("<H", header, 18)[0] != 243):
raise ValueError(f"expected a little-endian RV64 ELF: {path}")
def require_revision(root: Path, name: str) -> Path:
spec = load_lock(root / "dependencies/dependencies.lock.json")["sources"][name]
source = root / spec["destination"]
actual = subprocess.check_output(["git", "-C", str(source), "rev-parse", "HEAD"], text=True).strip()
if actual != spec["revision"]:
raise ValueError(f"{name} revision mismatch: {actual} != {spec['revision']}")
if subprocess.run(["git", "-C", str(source), "diff", "--quiet", "HEAD", "--"],
check=False).returncode:
raise ValueError(f"{name} has modified tracked source files: {source}")
return source
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True)
print(cross_prefix(parser.parse_args().root.resolve()))
+24 -9
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Package LP firmware and the fixed HP Linux image set into one flash image."""
"""Package LP firmware and a typed RV64 HP workload into a V2 flash image."""
from __future__ import annotations
@@ -15,7 +15,7 @@ FLASH_SIZE = 16 * 1024 * 1024
BUNDLE_OFFSET = 1 * 1024 * 1024
PAYLOAD_ALIGNMENT = 4096
MAGIC = 0x50485352
VERSION = 1
VERSION = 2
REQUIRED = 1
HEADER = struct.Struct("<8I")
ENTRY = struct.Struct("<6I")
@@ -23,9 +23,19 @@ ARTIFACTS = (
(1, "fw_jump.bin", 0x38000000, 512 * 1024),
(2, "retrosoc_hp.dtb", 0x38080000, 64 * 1024),
(3, "Image", 0x38400000, 12 * 1024 * 1024),
(4, "rootfs.cpio.gz", 0x39000000, 8 * 1024 * 1024),
(4, "rootfs.cpio", 0x39000000, 8 * 1024 * 1024),
)
HEADER_SIZE = HEADER.size + (ENTRY.size * len(ARTIFACTS))
WORKLOADS = {"linux": 1, "smoke": 2, "rtthread": 3}
def artifacts_for(workload: str) -> tuple[tuple[int, str, int, int], ...]:
if workload == "linux":
return ARTIFACTS
if workload not in WORKLOADS:
raise ValueError(f"unsupported HP workload: {workload}")
name = "hp_smoke.bin" if workload == "smoke" else "rtthread.bin"
return ((5, name, 0x38000000, 512 * 1024),)
def align_up(value: int, alignment: int) -> int:
@@ -37,6 +47,8 @@ def sha256(data: bytes) -> str:
def package(args: argparse.Namespace) -> None:
workload = getattr(args, "workload", "linux")
artifacts = artifacts_for(workload)
firmware = args.firmware.read_bytes()
if len(firmware) > BUNDLE_OFFSET:
raise ValueError(
@@ -48,7 +60,7 @@ def package(args: argparse.Namespace) -> None:
payloads: list[tuple[int, bytes]] = []
artifact_manifest: dict[str, object] = {}
cursor = payload_offset
for kind, name, load_address, maximum in ARTIFACTS:
for kind, name, load_address, maximum in artifacts:
data = (args.images / name).read_bytes()
if not data or len(data) > maximum:
raise ValueError(f"{name} size {len(data)} is outside 1..{maximum} bytes")
@@ -75,8 +87,8 @@ def package(args: argparse.Namespace) -> None:
total_size,
0,
REQUIRED,
0,
) + b"".join(entries)
WORKLOADS[workload],
) + b"".join(entries).ljust(HEADER_SIZE - HEADER.size, b"\0")
header_crc32 = zlib.crc32(header) & 0xFFFFFFFF
header = HEADER.pack(
MAGIC,
@@ -86,8 +98,8 @@ def package(args: argparse.Namespace) -> None:
total_size,
header_crc32,
REQUIRED,
0,
) + b"".join(entries)
WORKLOADS[workload],
) + b"".join(entries).ljust(HEADER_SIZE - HEADER.size, b"\0")
image = bytearray(b"\xFF" * cursor)
image[: len(firmware)] = firmware
@@ -99,7 +111,9 @@ def package(args: argparse.Namespace) -> None:
args.output.write_bytes(image)
manifest = {
"schema_version": 1,
"format": "retrosoc-hp-boot-bundle-v1",
"format": "retrosoc-hp-boot-bundle-v2",
"workload": workload,
"xlen": 64,
"bundle_offset": f"0x{BUNDLE_OFFSET:08X}",
"flash_capacity_bytes": FLASH_SIZE,
"header_crc32": f"0x{header_crc32:08X}",
@@ -120,6 +134,7 @@ def main() -> None:
parser.add_argument("--images", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--manifest", type=Path, required=True)
parser.add_argument("--workload", choices=WORKLOADS, default="linux")
package(parser.parse_args())
+6 -1
View File
@@ -111,6 +111,11 @@ def main() -> int:
args.result.parent.mkdir(parents=True, exist_ok=True)
started = datetime.now(timezone.utc)
start_clock = time.monotonic()
atomic_write(args.result, json.dumps({
"schema_version": 1, "tool": args.tool, "command": command,
"started_at": started.isoformat(), "status": "running",
"log": str(args.log.resolve()),
}, indent=2, sort_keys=True) + "\n")
returncode = 127
error_message = None
process: subprocess.Popen[str] | subprocess.Popen[bytes] | None = None
@@ -183,7 +188,7 @@ def main() -> int:
"finished_at": finished.isoformat(),
"duration_seconds": round(time.monotonic() - start_clock, 3),
"exit_code": returncode,
"status": "passed" if returncode == 0 else "failed",
"status": "interrupted" if returncode == 130 else ("passed" if returncode == 0 else "failed"),
"log": str(args.log.resolve()),
}
if error_message:
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""Run and validate one HP workload without reusing another workload's verdict."""
from __future__ import annotations
import argparse
import json
import subprocess
import sys
from pathlib import Path
MARKERS = {
"smoke": ("HP_LINUX_READY", "HP_GA2D_PASS", "HP_GA2D_CACHE_CLEAN"),
"linux": ("HP_LINUX_INIT_PASS", "retroSoC HP Linux ready", "HP_LINUX_READY"),
"rtthread": ("RTTHREAD_RV64_PASS", "RTTHREAD_TIMEOUT_PASS", "RTTHREAD_PREEMPT_PASS",
"RTTHREAD_CONTEXT_PASS", "RTTHREAD_IPC_PASS", "RTTHREAD_MAILBOX_IRQ_PASS",
"RTTHREAD_TEST_PASS", "HP_RTTHREAD_PASS"),
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--emulator", type=Path, required=True)
parser.add_argument("--image", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--workload", choices=MARKERS, required=True)
parser.add_argument("--timeout", type=int, required=True)
args = parser.parse_args()
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
result = output / "result-sim-check.json"
result.write_text(json.dumps({"status": "running", "workload": args.workload}) + "\n",
encoding="utf-8")
scripts = Path(__file__).resolve().parent
try:
process = subprocess.run([
sys.executable, str(scripts / "run_flow.py"), "--tool", "verilator-sim",
"--stream-bytes", "--log", str(output / "sim.log"), "--result",
str(output / "result-sim.json"), "--cwd", str(output), "--",
str(args.emulator.resolve()), "-i", str(args.image.resolve()),
"--fast-flash", "-t", str(args.timeout),
], check=False)
if process.returncode:
result.write_text(json.dumps({"status": "failed", "exit_code": process.returncode})
+ "\n", encoding="utf-8")
return process.returncode
command = [sys.executable, str(scripts / "check_simulation.py"), "--log",
str(output / "sim.log"), "--result", str(result)]
for marker in ("VERILATOR_FAST_FLASH=enabled", "SIM_TEST_PASS code=0",
*MARKERS[args.workload]):
command.extend(("--require", marker))
return subprocess.run(command, check=False).returncode
except KeyboardInterrupt:
result.write_text('{"status": "interrupted"}\n', encoding="utf-8")
return 130
if __name__ == "__main__":
raise SystemExit(main())
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Install the locked RT-Thread source, RV64 compiler and SCons environment."""
from __future__ import annotations
import argparse
import venv
from pathlib import Path
from dependency_lock import load_lock
from install_toolchain import install
from setup_helpers import ensure_git_repo, run
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--update", action="store_true")
args = parser.parse_args()
root = Path(__file__).resolve().parents[1]
lock = load_lock()
spec = lock["sources"]["rtthread_hp"]
ensure_git_repo(spec["url"], root / spec["destination"], spec["revision"], update=args.update)
install("riscv_gnu_hp", lock["toolchains"]["ubuntu-22.04"]["riscv_gnu_hp"],
root / ".cache/retrosoc/development", args.update)
environment = root / ".cache/retrosoc/rtthread-venv"
if not (environment / "bin/python").is_file():
venv.EnvBuilder(with_pip=True).create(environment)
run((str(environment / "bin/python"), "-m", "pip", "install", "--require-hashes",
"--cache-dir", str(root / ".cache/retrosoc/pip"),
"-r", str(root / "requirements/rtthread.txt")))
if __name__ == "__main__":
main()
+2 -2
View File
@@ -8,7 +8,7 @@ import vexiiriscv.misc.EmbeddedRiscvJtag
import java.nio.file.{Files, Paths}
/** Generates the fixed retroSoC RV32 Linux application core. */
/** Generates the fixed retroSoC RV64 application core. */
object GenerateRetroSocHp extends App {
require(args.length == 1, "usage: GenerateRetroSocHp <output-directory>")
@@ -16,7 +16,7 @@ object GenerateRetroSocHp extends App {
Files.createDirectories(output)
val param = new ParamSimple()
param.xlen = 32
param.xlen = 64
param.physicalWidth = 32
param.resetVector = 0x38000000L
param.asidWidth = 9