mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- Replaced instances of nmi_if with rib_if in sysctrl_fault_tb.sv, test_dma.py, test_gpio_user_mux.py, test_memory_map.py, test_performance_log.py, test_script_tools.py, test_sdram.py, test_soc_topology.py, test_sta_constraints.py, and test_user_extensions.py. - Updated test cases to reflect changes from NMI to RIB, ensuring all references and assertions are consistent with the new interface. - Adjusted memory map and performance log tests to validate RIB-specific configurations and behaviors. - Ensured that all relevant file paths and definitions are updated to maintain functionality and correctness across the test suite.
310 lines
11 KiB
Python
310 lines
11 KiB
Python
"""Tests for the canonical Mini SoC address-map generator."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
GENERATOR = ROOT / "rtl/mini/address_map/generate_memory_map.py"
|
|
MEMORY_MAP = ROOT / "rtl/mini/address_map/memory_map.json"
|
|
USER_EXTENSIONS = ROOT / "rtl/mini/integration/user_extensions.json"
|
|
USER_GENERATOR = ROOT / "rtl/mini/integration/generate_user_extensions.py"
|
|
|
|
|
|
def generate(output_dir: Path, *, sram: str = "NO") -> None:
|
|
subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(GENERATOR),
|
|
"--map",
|
|
str(MEMORY_MAP),
|
|
"--output-dir",
|
|
str(output_dir),
|
|
"--have-sram-if",
|
|
sram,
|
|
],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(USER_GENERATOR),
|
|
"--map",
|
|
str(USER_EXTENSIONS),
|
|
"--output-dir",
|
|
str(output_dir / "user_extensions"),
|
|
],
|
|
check=True,
|
|
)
|
|
|
|
|
|
def test_generated_artifacts_share_the_capacity_baseline(tmp_path: Path) -> None:
|
|
generate(tmp_path, sram="YES")
|
|
|
|
rtl = (tmp_path / "rtl/mmap_define.svh").read_text(encoding="utf-8")
|
|
header = (tmp_path / "include/retrosoc/generated/memory_map.h").read_text(encoding="utf-8")
|
|
linker = (tmp_path / "linker/memory_regions.ld").read_text(encoding="utf-8")
|
|
|
|
assert "`define SOC_ADDR_PSRAM_END 32'h407FFFFF" in rtl
|
|
assert "`define SOC_ADDR_XPI_END 32'h5FFFFFFF" in rtl
|
|
assert "`define SOC_ADDR_IS_FLASH(addr) ((addr) <= `SOC_ADDR_FLASH_END)" in rtl
|
|
assert "`define CPU_RESET_ADDR `SOC_CPU_RESET_ADDR" in rtl
|
|
assert "`define SOC_ADDR_IS_RESERVED(addr)" in rtl
|
|
assert "RS_SOC_PSRAM_SIZE UINT32_C(0x00800000)" in header
|
|
assert "RS_SOC_SDRAM_SIZE UINT32_C(0x02000000)" in header
|
|
assert "RS_SOC_SPISD_SIZE UINT32_C(0x40000000)" in header
|
|
assert "RS_SOC_RIB_SDIO_BASE" not in header
|
|
assert "RS_SOC_NMI_" not in header
|
|
assert "RS_SOC_OPIPSRAM_BASE" not in header
|
|
assert "RS_SOC_HAS_SRAM 1U" in header
|
|
assert "SOC_SYSCTRL_PLL_CFG_OFFSET 32'h00000008" in rtl
|
|
assert "SOC_SYSCTRL_PLL_STATUS_OFFSET 32'h0000001C" in rtl
|
|
assert "SOC_ADDR_IS_RIB(addr)" in rtl
|
|
assert "SOC_ADDR_IS_NMI" not in rtl
|
|
assert "RS_SOC_SYSCTRL_PLL_CFG_OFFSET UINT32_C(0x00000008)" in header
|
|
assert "RS_SOC_SYSCTRL_PLL_STATUS_OFFSET UINT32_C(0x0000001C)" in header
|
|
assert "PSRAM (wxa!ri) : ORIGIN = 0x40000000, LENGTH = 0x00800000" in linker
|
|
|
|
|
|
def test_user_ip_is_always_emitted_for_the_fixed_platform(tmp_path: Path) -> None:
|
|
generate(tmp_path)
|
|
|
|
rtl = (tmp_path / "rtl/mmap_define.svh").read_text(encoding="utf-8")
|
|
header = (tmp_path / "include/retrosoc/generated/memory_map.h").read_text(encoding="utf-8")
|
|
|
|
assert "SOC_ADDR_APB_USER_IP_BASE" in rtl
|
|
assert "RS_SOC_APB_USER_IP_BASE" in header
|
|
|
|
|
|
def test_map_validation_rejects_overlaps(tmp_path: Path) -> None:
|
|
document = json.loads(MEMORY_MAP.read_text(encoding="utf-8"))
|
|
document["regions"][1]["base"] = document["regions"][0]["base"]
|
|
invalid_map = tmp_path / "overlap.json"
|
|
invalid_map.write_text(json.dumps(document), encoding="utf-8")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, str(GENERATOR), "--map", str(invalid_map), "--check"],
|
|
text=True,
|
|
capture_output=True,
|
|
)
|
|
|
|
assert result.returncode != 0
|
|
assert "address-map overlap" in result.stderr
|
|
|
|
|
|
def test_bus_fault_responder_handles_reserved_and_unmapped_addresses(tmp_path: Path) -> None:
|
|
iverilog = shutil.which("iverilog")
|
|
vvp = shutil.which("vvp")
|
|
if iverilog is None or vvp is None:
|
|
return
|
|
generate(tmp_path)
|
|
simulation = tmp_path / "bus_fault_tb"
|
|
source_list = tmp_path / "bus_fault.fl"
|
|
source_list.write_text(
|
|
"\n".join(
|
|
[
|
|
"+define+SV_ASSRT_DISABLE",
|
|
f"+incdir+{tmp_path / 'rtl'}",
|
|
f"+incdir+{tmp_path / 'user_extensions' / 'rtl'}",
|
|
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/rib_if.sv"),
|
|
str(ROOT / "rtl/mini/top/soc_rib_if.sv"),
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
|
str(ROOT / "rtl/mini/top/soc_rib_regslice.sv"),
|
|
str(ROOT / "rtl/mini/top/bus.sv"),
|
|
str(ROOT / "tests/rtl/bus_fault_tb.sv"),
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
converted = tmp_path / "bus_fault_tb.v"
|
|
subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
|
"-f",
|
|
str(source_list),
|
|
"--output",
|
|
str(converted),
|
|
],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
iverilog,
|
|
"-g2012",
|
|
"-s",
|
|
"bus_fault_tb",
|
|
"-o",
|
|
str(simulation),
|
|
str(converted),
|
|
],
|
|
check=True,
|
|
)
|
|
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
|
assert "bus fault responder test passed" in result.stdout
|
|
|
|
|
|
def test_sysctrl_fault_registers_record_and_clear_pending(tmp_path: Path) -> None:
|
|
iverilog = shutil.which("iverilog")
|
|
vvp = shutil.which("vvp")
|
|
if iverilog is None or vvp is None:
|
|
return
|
|
generate(tmp_path)
|
|
source_list = tmp_path / "sysctrl_fault.fl"
|
|
source_list.write_text(
|
|
"\n".join(
|
|
[
|
|
"+define+SV_ASSRT_DISABLE",
|
|
f"+incdir+{tmp_path / 'rtl'}",
|
|
f"+incdir+{tmp_path / 'user_extensions' / 'rtl'}",
|
|
f"+incdir+{ROOT / 'rtl/mini/top'}",
|
|
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/rib_if.sv"),
|
|
str(ROOT / "rtl/mini/top/soc_rib_if.sv"),
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
|
str(ROOT / "rtl/ip/rib/peripheral/pll_ctrl_if.sv"),
|
|
str(ROOT / "rtl/ip/rib/peripheral/sysctrl.sv"),
|
|
str(ROOT / "tests/rtl/sysctrl_fault_tb.sv"),
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
converted = tmp_path / "sysctrl_fault_tb.v"
|
|
subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
|
"-f",
|
|
str(source_list),
|
|
"--output",
|
|
str(converted),
|
|
],
|
|
check=True,
|
|
)
|
|
simulation = tmp_path / "sysctrl_fault_tb"
|
|
subprocess.run(
|
|
[iverilog, "-g2012", "-s", "sysctrl_fault_tb", "-o", str(simulation), str(converted)],
|
|
check=True,
|
|
)
|
|
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
|
assert "sysctrl fault and user core control test passed" in result.stdout
|
|
|
|
|
|
def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path: Path) -> None:
|
|
iverilog = shutil.which("iverilog")
|
|
vvp = shutil.which("vvp")
|
|
if iverilog is None or vvp is None:
|
|
return
|
|
generate(tmp_path)
|
|
source_list = tmp_path / "pll_ctrl.fl"
|
|
source_list.write_text(
|
|
"\n".join(
|
|
[
|
|
"+define+SV_ASSRT_DISABLE",
|
|
"+define+PDK_BEHAV",
|
|
"+define+HAVE_PLL",
|
|
f"+incdir+{tmp_path / 'rtl'}",
|
|
f"+incdir+{tmp_path / 'user_extensions' / 'rtl'}",
|
|
f"+incdir+{ROOT / 'rtl/mini/top'}",
|
|
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/rib_if.sv"),
|
|
str(ROOT / "rtl/mini/top/soc_rib_if.sv"),
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv"),
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_2phase.sv"),
|
|
str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/rst_sync.sv"),
|
|
str(ROOT / "rtl/ip/rib/peripheral/pll_ctrl_if.sv"),
|
|
str(ROOT / "rtl/ip/rib/peripheral/sysctrl.sv"),
|
|
str(ROOT / "rtl/tech/tc_clk.sv"),
|
|
str(ROOT / "rtl/tech/tc_pll.sv"),
|
|
str(ROOT / "rtl/mini/top/rcu.sv"),
|
|
str(ROOT / "tests/rtl/pll_ctrl_tb.sv"),
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
converted = tmp_path / "pll_ctrl_tb.v"
|
|
subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
|
"-f",
|
|
str(source_list),
|
|
"--output",
|
|
str(converted),
|
|
],
|
|
check=True,
|
|
)
|
|
simulation = tmp_path / "pll_ctrl_tb"
|
|
subprocess.run(
|
|
[iverilog, "-g2012", "-s", "pll_ctrl_tb", "-o", str(simulation), str(converted)],
|
|
check=True,
|
|
)
|
|
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
|
assert "pll controller dynamic configuration test passed" in result.stdout
|
|
result = subprocess.run(
|
|
[vvp, str(simulation), "+pll_lock_fail"], text=True, capture_output=True, check=True
|
|
)
|
|
assert "pll controller timeout test passed" in result.stdout
|
|
|
|
unsupported_list = tmp_path / "pll_unsupported.fl"
|
|
unsupported_list.write_text(
|
|
source_list.read_text(encoding="utf-8").replace("+define+HAVE_PLL\n", ""),
|
|
encoding="utf-8",
|
|
)
|
|
unsupported_converted = tmp_path / "pll_unsupported_tb.v"
|
|
subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
|
"-f",
|
|
str(unsupported_list),
|
|
"--output",
|
|
str(unsupported_converted),
|
|
],
|
|
check=True,
|
|
)
|
|
unsupported_simulation = tmp_path / "pll_unsupported_tb"
|
|
subprocess.run(
|
|
[
|
|
iverilog,
|
|
"-g2012",
|
|
"-s",
|
|
"pll_ctrl_tb",
|
|
"-o",
|
|
str(unsupported_simulation),
|
|
str(unsupported_converted),
|
|
],
|
|
check=True,
|
|
)
|
|
result = subprocess.run(
|
|
[vvp, str(unsupported_simulation)], text=True, capture_output=True, check=True
|
|
)
|
|
assert "pll controller capability gate test passed" in result.stdout
|
|
|
|
|
|
def test_sysctrl_does_not_expose_unused_i2c_or_qspi_select_registers() -> None:
|
|
rtl = (ROOT / "rtl/ip/rib/peripheral/sysctrl.sv").read_text(encoding="utf-8")
|
|
header = (ROOT / "crt/include/retrosoc/core/soc.h").read_text(encoding="utf-8")
|
|
|
|
for symbol in (
|
|
"RIB_SYSCTRL_I2CSEL",
|
|
"RIB_SYSCTRL_QSPISEL",
|
|
"i2c_sel_o",
|
|
"qspi_sel_o",
|
|
"s_sysctrl_i2csel",
|
|
"s_sysctrl_qspisel",
|
|
):
|
|
assert symbol not in rtl
|
|
assert "reg_sysctrl_i2csel" not in header
|
|
assert "reg_sysctrl_qspicsel" not in header
|