Files
retroSoC/tests/test_sdram.py
T
maksyuki a32d9af957 feat: enhance SDRAM Controller and Testbench Functionality
- Introduced burst length handling in the SDRAM Verilator model, allowing for more flexible read/write operations.
- Added new SDRAM-related source files to the project structure, including sdram_pkg.sv and sdram_axi4.sv.
- Updated software makefile to include new SDRAM-related C source files for HAL.
- Enhanced C test suite with new tests for SDRAM timing and functionality, ensuring proper integration with the HAL.
- Improved RTL testbench for SDRAM, adding support for burst writes and reads, and verifying data integrity.
- Updated Python test scripts to reflect changes in SDRAM handling and ensure comprehensive coverage of SDRAM functionality.
- Added checks to ensure register offsets between RTL and HAL definitions match, maintaining consistency across the codebase.
2026-08-18 09:06:19 +08:00

175 lines
5.8 KiB
Python

"""SDRAM controller data-integrity regression."""
from __future__ import annotations
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def _write_memory_map(generated: Path) -> None:
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/address_map/generate_memory_map.py"),
"--map",
str(ROOT / "rtl/mini/address_map/memory_map.json"),
"--output-dir",
str(generated),
],
check=True,
)
def _source_list_text(generated: Path, *, timing_model: bool) -> str:
lines = [
"+define+SV_ASSRT_DISABLE",
f"+incdir+{generated / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl/interface'}",
f"+incdir+{ROOT / 'rtl/ip/memory'}",
]
if timing_model:
lines.append("+define+SDRAM_TIMING_MODEL")
lines.append(f"+incdir+{ROOT / 'rtl/managed/third_party/model/sdram'}")
lines.extend(
[
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_addr_gen.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv"),
str(ROOT / "rtl/ip/memory/sdram_pkg.sv"),
str(ROOT / "rtl/ip/memory/axi4_sdram.sv"),
str(ROOT / "rtl/ip/memory/sdram_clkgen.sv"),
str(ROOT / "rtl/ip/memory/sdram_reg.sv"),
str(ROOT / "rtl/ip/memory/sdram_axi4.sv"),
str(ROOT / "rtl/ip/memory/sdram_core.sv"),
]
)
if not timing_model:
lines.append(str(ROOT / "rtl/mini/dv/verilator/rtl/sdram_verilator_model.sv"))
lines.append(str(ROOT / "tests/rtl/sdram_data_tb.sv"))
lines.append("")
return "\n".join(lines)
def test_sdram_controller_preserves_full_and_masked_writes(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
if iverilog is None or vvp is None:
return
generated = tmp_path / "generated"
_write_memory_map(generated)
source_list = tmp_path / "sdram_data.fl"
source_list.write_text(_source_list_text(generated, timing_model=False), encoding="utf-8")
converted = tmp_path / "sdram_data_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 / "sdram_data_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "sdram_data_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "sdram data integrity test passed" in result.stdout
def test_sdram_controller_preserves_data_with_micron_timing_model(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
if iverilog is None or vvp is None:
return
generated = tmp_path / "generated"
_write_memory_map(generated)
source_list = tmp_path / "sdram_timing.fl"
source_list.write_text(_source_list_text(generated, timing_model=True), encoding="utf-8")
converted = tmp_path / "sdram_timing_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 / "sdram_timing_tb"
subprocess.run(
[
iverilog,
"-g2012",
"-s",
"sdram_data_tb",
"-I",
str(ROOT / "rtl/managed/third_party/model/sdram"),
"-o",
str(simulation),
str(converted),
str(ROOT / "rtl/managed/third_party/model/sdram/sdr.v"),
],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "sdram data integrity test passed" in result.stdout
def test_sdram_handwritten_register_offsets_match_hal() -> None:
import re
rtl_text = (ROOT / "rtl/ip/memory/sdram_define.svh").read_text(encoding="utf-8")
hal_text = (ROOT / "crt/src/hal/sdram.c").read_text(encoding="utf-8")
rtl_offsets = {
name: int(value, 16)
for name, value in re.findall(
r"`define\s+APB4_SDRAM__([A-Z0-9_]+)\s+12'h([0-9A-Fa-f]+)",
rtl_text,
)
}
hal_offsets = {
name: int(value, 16)
for name, value in re.findall(
r"#define\s+RS_SDRAM_([A-Z0-9_]+)_OFFSET\s+UINT32_C\(0x([0-9A-Fa-f]+)\)",
hal_text,
)
}
assert hal_offsets
for name, value in hal_offsets.items():
assert rtl_offsets[name] == value
def test_sdram_register_macros_live_in_hal_not_soc() -> None:
soc_text = (ROOT / "crt/include/retrosoc/core/soc.h").read_text(encoding="utf-8")
header_text = (ROOT / "crt/include/retrosoc/hal/sdram.h").read_text(encoding="utf-8")
assert "reg_sdram_" not in soc_text
assert "reg_sdram_" not in header_text
def test_ci_software_covers_sdram_mapped_window() -> None:
smoke = (ROOT / "app/apps/ci_smoke/main.c").read_text(encoding="utf-8")
hello = (ROOT / "app/asm/hello.s").read_text(encoding="utf-8")
assert "rs_ci_smoke_sdram_access" in smoke
assert "RS_SOC_SDRAM_BASE" in smoke
assert "RS_SOC_SDRAM_BASE" in hello
assert "WAIT_SDRAM_READY" in hello