mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
# Conflicts: # Makefile # README.md # app/README.md # app/apps/hp_boot/main.c # configs/README.md # dependencies/dependencies.lock.json # publications/datasheets/sections/architecture.typ # publications/datasheets/sections/boot-bundle-format.typ # publications/datasheets/sections/linux-runtime.typ # publications/datasheets/sections/overview.typ # publications/datasheets/system-reference.json # publications/software_reference.py # scripts/build_hp_smoke.py # scripts/run_flow.py
248 lines
9.4 KiB
Python
248 lines
9.4 KiB
Python
"""HP platform configuration and generated-source boundary tests."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from scripts import build_hp_linux
|
|
from scripts.run_hp_sim import MARKERS
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def test_hp_profile_and_locked_generator_contract() -> None:
|
|
lock = json.loads((ROOT / "dependencies/dependencies.lock.json").read_text(encoding="utf-8"))
|
|
vexii = lock["sources"]["vexiiriscv"]
|
|
assert vexii["revision"] == "ef7da4134ff11ec6a681d0632123b232b853b046"
|
|
assert vexii["recursive"] is True
|
|
assert vexii["destination"].startswith(".cache/")
|
|
|
|
profile = (ROOT / "configs/ci/ihp130-hp.mk").read_text(encoding="utf-8")
|
|
assert "HAVE_HP" in profile and "YES" in profile
|
|
assert "rv64imafdc_zicbom_max" in profile
|
|
assert "APP" in profile and "hp_boot" in profile
|
|
assert "LINK_TYPE" in profile and "ld2_all_sram" in profile
|
|
|
|
generator = (ROOT / "scripts/vexiiriscv/GenerateRetroSocHp.scala").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
for requirement in (
|
|
"param.xlen = 64",
|
|
"param.physicalWidth = 32",
|
|
'param.addISA("m", "a", "f", "d", "c", "s", "u", "zicbom", "zicntr", "zihpm")',
|
|
"param.decoders = 2",
|
|
"param.lanes = 2",
|
|
"param.fetchL1Ways = 4",
|
|
"param.lsuL1Ways = 4",
|
|
"param.resetVector = 0x38000000L",
|
|
"param.plugins(hartId = 1)",
|
|
):
|
|
assert requirement in generator
|
|
|
|
|
|
def test_makefile_uses_path_resolved_sbt() -> None:
|
|
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
|
|
assert "SBT ?= sbt" in makefile
|
|
assert "/nfs/home/miaoyuchi/sbt/bin/sbt" not in makefile
|
|
|
|
|
|
def test_hp_linux_simulation_uses_explicit_fast_flash_acceptance() -> None:
|
|
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
|
|
verilator_makefile = (ROOT / "rtl/mini/mk/verilator.mk").read_text(encoding="utf-8")
|
|
emulator = (ROOT / "rtl/mini/dv/verilator/csrc/main.cpp").read_text(encoding="utf-8")
|
|
|
|
assert "HP_LINUX_SIM_TIME ?= 0" in makefile
|
|
assert "hp-linux-sim: hp-bundle comp" in makefile
|
|
assert "--workload linux --timeout $(HP_LINUX_SIM_TIME)" in makefile
|
|
for marker in (
|
|
"VERILATOR_FAST_FLASH=enabled",
|
|
"retroSoC HP Linux ready",
|
|
"HP_LINUX_READY",
|
|
"SIM_TEST_PASS code=0",
|
|
):
|
|
assert marker in (*MARKERS["linux"], "SIM_TEST_PASS code=0", "VERILATOR_FAST_FLASH=enabled")
|
|
assert "VERILATOR_SIM_ARGS ?=" in verilator_makefile
|
|
assert "$(VERILATOR_SIM_ARGS) -t $(SOC_SIM_TIME)" in verilator_makefile
|
|
assert '("fast-flash"' in emulator
|
|
|
|
|
|
def test_hp_address_and_sysctrl_contract() -> None:
|
|
document = json.loads(
|
|
(ROOT / "rtl/mini/address_map/memory_map.json").read_text(encoding="utf-8")
|
|
)
|
|
regions = {region["symbol"]: region for region in document["regions"]}
|
|
assert regions["HP_ACLINT"]["base"] == "0x02000000"
|
|
assert regions["HP_PLIC"]["base"] == "0x0C000000"
|
|
assert regions["APB4_UART1"]["base"] == "0x10018000"
|
|
assert regions["APB4_HP_MAILBOX"]["base"] == "0x10019000"
|
|
assert regions["APB4_RESOURCE_CTRL"]["base"] == "0x2000A000"
|
|
|
|
registers = {register["symbol"]: register["offset"] for register in document["sysctrl_registers"]}
|
|
assert registers["HP_CTRL"] == "0xA4"
|
|
assert registers["HP_STATUS"] == "0xA8"
|
|
assert registers["DEBUG_SELECT"] == "0xAC"
|
|
|
|
|
|
def test_generated_vexii_rtl_is_not_tracked() -> None:
|
|
tracked = subprocess.run(
|
|
["git", "ls-files", "*vexii_riscv_hp_generated*"],
|
|
cwd=ROOT,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
).stdout
|
|
assert tracked == ""
|
|
|
|
|
|
def test_hp_smoke_payload_uses_hart1_platform_abi() -> None:
|
|
source = (ROOT / "app/ports/linux/smoke/start.S").read_text(encoding="utf-8")
|
|
assert "0x10018000" in source
|
|
assert "0x10019000" in source
|
|
assert "0x4c4e5801" in source.lower()
|
|
assert "HP_SMOKE_READY" in source
|
|
assert "0x10012000" in source
|
|
assert "0x2000a000" in source.lower()
|
|
assert "cbo.clean" in source
|
|
assert "cbo.inval" in source
|
|
assert source.count(".balign 64") >= 4
|
|
for marker in ("HP_GA2D_START", "HP_GA2D_PASS", "HP_GA2D_FAIL", "HP_GA2D_CACHE"):
|
|
assert marker in source
|
|
|
|
|
|
def test_hp_smoke_p5_npu_payload_has_stack_cache_and_polling_plan() -> None:
|
|
source = (ROOT / "app/ports/linux/smoke/start.S").read_text(encoding="utf-8")
|
|
linker = (ROOT / "app/ports/linux/smoke/linker.ld").read_text(encoding="utf-8")
|
|
acceptance = (ROOT / "app/ports/linux/smoke/npu_acceptance.c").read_text(encoding="utf-8")
|
|
builder = (ROOT / "scripts/build_hp_smoke.py").read_text(encoding="utf-8")
|
|
|
|
assert "la sp, _stack_top" in source
|
|
assert "call rs_hp_npu_acceptance" in source
|
|
assert "_bss_start" in linker and "_bss_end" in linker and "_stack_top" in linker
|
|
assert "rs_kws_npu_execute" in acceptance
|
|
assert "rs_npu_irq_enable(0U)" in acceptance
|
|
assert "rs_npu_irq_ack(RS_NPU_IRQ_ALL)" in acceptance
|
|
assert '"--extra-source"' in builder and '"--include"' in builder
|
|
|
|
|
|
def test_hp_smoke_simulation_requires_ga2d_result_and_cache_lifecycle_markers() -> None:
|
|
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
|
|
target = makefile.split("hp-smoke-sim: hp-smoke-bundle comp", 1)[1].split("\nifeq", 1)[0]
|
|
|
|
assert "HP_SMOKE_SIM_TIME ?= 300" in makefile
|
|
assert "--workload smoke --timeout $(HP_SMOKE_SIM_TIME)" in target
|
|
|
|
for marker in (
|
|
"SIM_TEST_PASS code=0",
|
|
"HP_LINUX_READY",
|
|
"HP_GA2D_PASS",
|
|
"HP_GA2D_CACHE_CLEAN",
|
|
):
|
|
assert marker in (*MARKERS["smoke"], "SIM_TEST_PASS code=0")
|
|
|
|
|
|
def test_hp_cache_handshake_budget_covers_cbo_and_mailbox_round_trip() -> None:
|
|
source = (ROOT / "rtl/mini/top/retrosoc.sv").read_text(encoding="utf-8")
|
|
|
|
assert "HpCacheHandshakeTimeout = 16'hffff" in source
|
|
assert ".timeout_i (HpCacheHandshakeTimeout)" in source
|
|
|
|
|
|
def test_hp_lifecycle_flush_preserves_unadmitted_lp_requests() -> None:
|
|
source = (ROOT / "rtl/mini/top/soc_data_plane.sv").read_text(encoding="utf-8")
|
|
lp_data_cdc = source.split(") u_lp_data_cdc (", 1)[1].split(");", 1)[0]
|
|
|
|
assert ".clear_i (1'b0)" in lp_data_cdc
|
|
assert "HP lifecycle flush invalidates HP transport" in lp_data_cdc
|
|
|
|
|
|
def test_linux_build_uses_external_opensbi_platform_and_actual_initrd_end() -> None:
|
|
build = (ROOT / "scripts/build_hp_linux.py").read_text(encoding="utf-8")
|
|
assert '"tinyconfig"' in build
|
|
assert 'environment.pop("MAKEOVERRIDES", None)' in build
|
|
assert '"PLATFORM=retrosoc_hp"' in build
|
|
assert 'f"PLATFORM_DIR={external / \'opensbi\'}"' in build
|
|
assert '"fdtput"' in build
|
|
assert '"linux,initrd-end"' in build
|
|
|
|
platform = (
|
|
ROOT / "app/ports/linux/opensbi/retrosoc_hp/platform.c"
|
|
).read_text(encoding="utf-8")
|
|
assert "s_hart_index_to_id[] = {1U}" in platform
|
|
assert "RETROSOC_HP_UART_BASE" in platform
|
|
assert "aclint_mtimer_cold_init" in platform
|
|
|
|
|
|
def test_hp_linux_effective_config_is_fail_closed(tmp_path: Path) -> None:
|
|
fragment = (ROOT / "app/ports/linux/linux/retrosoc_hp.config").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG:
|
|
assert f"{symbol}=y" in fragment
|
|
|
|
config = tmp_path / ".config"
|
|
valid = "".join(f"{symbol}=y\n" for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG)
|
|
config.write_text(valid, encoding="utf-8")
|
|
build_hp_linux.validate_linux_config(config)
|
|
|
|
config.write_text(valid.replace("CONFIG_BINFMT_ELF=y", "# CONFIG_BINFMT_ELF is not set"),
|
|
encoding="utf-8")
|
|
with pytest.raises(RuntimeError, match="CONFIG_BINFMT_ELF=n"):
|
|
build_hp_linux.validate_linux_config(config)
|
|
|
|
config.write_text(valid.replace("CONFIG_TTY=y\n", ""), encoding="utf-8")
|
|
with pytest.raises(RuntimeError, match="CONFIG_TTY=missing"):
|
|
build_hp_linux.validate_linux_config(config)
|
|
|
|
|
|
def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path) -> None:
|
|
dtc = shutil.which("dtc")
|
|
fdtput = shutil.which("fdtput")
|
|
fdtget = shutil.which("fdtget")
|
|
if dtc is None or fdtput is None or fdtget is None:
|
|
return
|
|
dtb = tmp_path / "retrosoc_hp.dtb"
|
|
subprocess.run(
|
|
[
|
|
dtc,
|
|
"-I",
|
|
"dts",
|
|
"-O",
|
|
"dtb",
|
|
"-o",
|
|
str(dtb),
|
|
str(ROOT / "app/ports/linux/linux/retrosoc_hp.dts"),
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
subprocess.run(
|
|
[fdtput, "-t", "x", str(dtb), "/chosen", "linux,initrd-end", "0x39123456"],
|
|
check=True,
|
|
)
|
|
initrd_end = subprocess.check_output(
|
|
[fdtget, "-t", "x", str(dtb), "/chosen", "linux,initrd-end"], text=True
|
|
).strip()
|
|
hart_id = subprocess.check_output(
|
|
[fdtget, "-t", "x", str(dtb), "/cpus/cpu@1", "reg"], text=True
|
|
).strip()
|
|
assert initrd_end == "39123456"
|
|
assert hart_id == "1"
|
|
reservation = subprocess.check_output(
|
|
[fdtget, "-t", "x", str(dtb), "/reserved-memory/opensbi@38000000", "reg"], text=True
|
|
).strip()
|
|
assert reservation == "38000000 80000"
|
|
properties = subprocess.check_output(
|
|
[fdtget, "-p", str(dtb), "/reserved-memory/opensbi@38000000"], text=True
|
|
).splitlines()
|
|
assert "no-map" in properties
|
|
dts = (ROOT / "app/ports/linux/linux/retrosoc_hp.dts").read_text(encoding="utf-8")
|
|
assert '"zicbom"' in dts
|
|
assert "riscv,cbom-block-size = <64>;" in dts
|