feat: refactor NMI interface and enhance performance logging

- Updated NMI interface references from  to  in multiple files for consistency.
- Added a new script  to convert UART performance records into structured JSON format.
- Enhanced the README documentation to include details about the new performance log parser.
- Implemented tests for the new performance log parser to ensure correct functionality.
- Added new test cases for DMA error handling and SDRAM data integrity to improve coverage.
- Updated existing test cases to accommodate changes in the NMI interface and added performance metrics.
- Refactored bus fault testbench to include fault code checks and improved error handling.
- Adjusted memory map generation and pin mapping tests to reflect recent changes in RTL structure.
This commit is contained in:
maksyuki committed 2026-08-02 10:21:09 +08:00
1 parent ed19891bf5
commit 0a6055134e
61 files changed
+2539 -433

No files matched your search

+18 -10
View File
@@ -9,10 +9,11 @@ module bus_fault_tb;
logic fault_reserved_o;
logic fault_access_o;
logic [ 1:0] fault_master_o;
logic [ 2:0] fault_code_o;
logic user_bus_idle_o;
nmi_if mgmt_nmi ();
nmi_if user_nmi ();
nmi_if dma_nmi ();
soc_nmi_if mgmt_nmi ();
soc_nmi_if user_nmi ();
soc_nmi_if dma_nmi ();
nmi_if natv_nmi ();
nmi_if apb_nmi ();
@@ -33,16 +34,20 @@ module bus_fault_tb;
.user_bus_idle_o (user_bus_idle_o),
.natv_nmi (natv_nmi),
.apb_nmi (apb_nmi),
.apb_resp_err_i (1'b0),
.perf_enable_i (1'b0),
.perf_clear_i (1'b0),
.fault_valid_o (fault_valid_o),
.fault_addr_o (fault_addr_o),
.fault_wstrb_o (fault_wstrb_o),
.fault_reserved_o (fault_reserved_o),
.fault_access_o (fault_access_o),
.fault_master_o (fault_master_o)
.fault_master_o (fault_master_o),
.fault_code_o (fault_code_o)
);
task automatic expect_fault(input logic [31:0] address, input logic [3:0] write_strobes,
input logic reserved);
input logic reserved, input logic [2:0] expected_code);
begin
@(negedge clk_i);
mgmt_nmi.addr = address;
@@ -51,11 +56,13 @@ module bus_fault_tb;
mgmt_nmi.valid = 1'b1;
while (!fault_valid_o) @(posedge clk_i);
if (fault_addr_o !== address || fault_wstrb_o !== write_strobes ||
fault_reserved_o !== reserved || fault_access_o || natv_nmi.valid || apb_nmi.valid) begin
fault_reserved_o !== reserved || fault_access_o || fault_code_o !== expected_code ||
natv_nmi.valid || apb_nmi.valid) begin
$fatal(1, "unexpected fault response for address %h", address);
end
while (!mgmt_nmi.ready) @(posedge clk_i);
if (mgmt_nmi.rdata !== 32'd0) begin
if (mgmt_nmi.rdata !== 32'd0 || !mgmt_nmi.resp_err ||
mgmt_nmi.resp_code !== expected_code) begin
$fatal(1, "fault response data must be zero");
end
@(negedge clk_i);
@@ -76,7 +83,8 @@ module bus_fault_tb;
$fatal(1, "user access was not denied locally");
end
while (!user_nmi.ready) @(posedge clk_i);
if (user_nmi.rdata !== 32'd0) begin
if (user_nmi.rdata !== 32'd0 || !user_nmi.resp_err ||
user_nmi.resp_code !== `SOC_NMI_RESP_PROTERR) begin
$fatal(1, "denied user response data must be zero");
end
@(negedge clk_i);
@@ -102,8 +110,8 @@ module bus_fault_tb;
repeat (2) @(posedge clk_i);
rst_n_i = 1'b1;
expect_fault(32'h1000_F000, 4'hF, 1'b1);
expect_fault(32'hA000_0000, 4'h0, 1'b0);
expect_fault(32'h1000_F000, 4'hF, 1'b1, `SOC_NMI_RESP_RESERVED);
expect_fault(32'hA000_0000, 4'h0, 1'b0, `SOC_NMI_RESP_DECERR);
expect_user_denied(32'h1000_B000, 4'hF);
$display("bus fault responder test passed");
$finish;
+97
View File
@@ -0,0 +1,97 @@
`timescale 1ns / 1ps
module dma_error_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [ 2:0] mode_i = 3'd0;
logic [31:0] srcaddr_i = 32'h3800_1000;
logic srcincr_i = 1'b1;
logic [31:0] dstaddr_i = 32'h4000_1000;
logic dstincr_i = 1'b1;
logic [31:0] xferlen_i = 32'd1;
logic start_i = 1'b0;
logic stop_i = 1'b0;
logic reset_i = 1'b0;
logic done_o;
logic error_o;
logic [ 2:0] error_code_o;
logic [31:0] error_addr_o;
logic [ 1:0] fsm_o;
logic error_mode = 1'b0;
integer write_count = 0;
dma_hw_trg_if hw_trg ();
soc_nmi_if nmi ();
always #5 clk_i = ~clk_i;
assign nmi.ready = nmi.valid;
assign nmi.rdata = 32'hA5A5_5A5A;
assign nmi.resp_err = error_mode && nmi.valid;
assign nmi.resp_code = error_mode ? `SOC_NMI_RESP_DECERR : `SOC_NMI_RESP_OK;
always @(posedge clk_i) begin
if (nmi.valid && nmi.ready && (|nmi.wstrb)) begin
write_count <= write_count + 1;
end
end
dma_core u_dma_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.mode_i (mode_i),
.srcaddr_i (srcaddr_i),
.srcincr_i (srcincr_i),
.dstaddr_i (dstaddr_i),
.dstincr_i (dstincr_i),
.xferlen_i (xferlen_i),
.start_i (start_i),
.stop_i (stop_i),
.reset_i (reset_i),
.done_o (done_o),
.error_o (error_o),
.error_code_o(error_code_o),
.error_addr_o(error_addr_o),
.fsm_o (fsm_o),
.hw_trg (hw_trg),
.nmi (nmi)
);
task automatic start_transfer;
begin
@(negedge clk_i);
start_i = 1'b1;
@(negedge clk_i);
start_i = 1'b0;
end
endtask
initial begin
hw_trg.i2s_tx_proc = 1'b0;
hw_trg.i2s_rx_proc = 1'b0;
hw_trg.qspi_tx_proc = 1'b0;
hw_trg.qspi_rx_proc = 1'b0;
repeat (2) @(posedge clk_i);
rst_n_i = 1'b1;
start_transfer();
wait (done_o);
@(negedge clk_i);
if (write_count != 1) begin
$fatal(1, "one-word DMA transfer issued %0d writes", write_count);
end
error_mode = 1'b1;
start_transfer();
wait (error_o);
@(negedge clk_i);
if (error_code_o !== `SOC_NMI_RESP_DECERR || error_addr_o !== srcaddr_i) begin
$fatal(1, "DMA error response was not propagated");
end
if (write_count != 1) begin
$fatal(1, "DMA issued a write after a read error");
end
$display("dma error responder test passed");
$finish;
end
endmodule
+110
View File
@@ -0,0 +1,110 @@
`timescale 1ns / 1ps
module sdram_data_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
wire [15:0] s_dq;
logic [31:0] s_read_data;
nmi_if nmi ();
sdram_if sdram ();
always #5 clk_i = ~clk_i;
assign s_dq = sdram.oe_o ? sdram.dq_o : 'z;
assign sdram.dq_i = s_dq;
nmi_sdram u_nmi_sdram (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.nmi (nmi),
.sdram (sdram)
);
`ifdef SDRAM_TIMING_MODEL
sdr u_sdr (
.Clk (sdram.clk_o),
.Cke (sdram.cke_o),
.Cs_n (sdram.cs_n_o),
.Ras_n(sdram.ras_n_o),
.Cas_n(sdram.cas_n_o),
.We_n (sdram.we_n_o),
.Addr (sdram.addr_o),
.Ba (sdram.ba_o),
.Dq (s_dq),
.Dqm (sdram.dqm_o)
);
`else
sdram_verilator_model u_sdram_verilator_model (
.clk_i (sdram.clk_o),
.cke_i (sdram.cke_o),
.cs_n_i (sdram.cs_n_o),
.ras_n_i(sdram.ras_n_o),
.cas_n_i(sdram.cas_n_o),
.we_n_i (sdram.we_n_o),
.ba_i (sdram.ba_o),
.addr_i (sdram.addr_o),
.dqm_i (sdram.dqm_o),
.dq_io (s_dq)
);
`endif
task automatic write_word(input logic [31:0] address, input logic [31:0] data,
input logic [3:0] strobe);
begin
@(negedge clk_i);
nmi.addr = address;
nmi.wdata = data;
nmi.wstrb = strobe;
nmi.valid = 1'b1;
do begin
@(posedge clk_i);
end while (!nmi.ready);
@(negedge clk_i);
nmi.valid = 1'b0;
nmi.wstrb = '0;
end
endtask
task automatic read_word(input logic [31:0] address);
begin
@(negedge clk_i);
nmi.addr = address;
nmi.wdata = '0;
nmi.wstrb = '0;
nmi.valid = 1'b1;
do begin
@(posedge clk_i);
end while (!nmi.ready);
s_read_data = nmi.rdata;
@(negedge clk_i);
nmi.valid = 1'b0;
end
endtask
initial begin
nmi.addr = '0;
nmi.valid = 1'b0;
nmi.wdata = '0;
nmi.wstrb = '0;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
// The controller waits 100 us after reset before accepting a request.
repeat (8000) @(posedge clk_i);
write_word(`SOC_ADDR_SDRAM_BASE, 32'h1234_5678, 4'b1111);
read_word(`SOC_ADDR_SDRAM_BASE);
if (s_read_data !== 32'h1234_5678) begin
$fatal(1, "full-word SDRAM readback was %08x", s_read_data);
end
write_word(`SOC_ADDR_SDRAM_BASE, 32'hA5A5_0000, 4'b1100);
read_word(`SOC_ADDR_SDRAM_BASE);
if (s_read_data !== 32'hA5A5_5678) begin
$fatal(1, "masked SDRAM readback was %08x", s_read_data);
end
$display("sdram data integrity test passed");
$finish;
end
endmodule
+31
View File
@@ -63,6 +63,15 @@ module sysctrl_fault_tb;
sysctrl.user_bus_idle_i = 1'b1;
sysctrl.fault_access_i = 1'b0;
sysctrl.fault_master_i = '0;
sysctrl.fault_code_i = `SOC_NMI_RESP_RESERVED;
sysctrl.perf_mgmt_wait_i = 64'd11;
sysctrl.perf_user_wait_i = 64'd12;
sysctrl.perf_dma_wait_i = 64'd13;
sysctrl.perf_natv_wait_i = 64'd14;
sysctrl.perf_apb_wait_i = 64'd15;
sysctrl.perf_sdram_wait_i = 64'd16;
sysctrl.perf_psram_wait_i = 64'd17;
sysctrl.perf_flash_wait_i = 64'd18;
pll_ctrl.req_ready_i = 1'b1;
pll_ctrl.rsp_active_sel_i = '0;
pll_ctrl.rsp_active_valid_i = 1'b0;
@@ -88,10 +97,32 @@ module sysctrl_fault_tb;
if (read_data !== 32'h1000_F000) $fatal(1, "fault address was not recorded");
read_register(32'h1000_B018, read_data);
if (read_data !== 32'h0000_0001) $fatal(1, "fault count was not incremented");
read_register(32'h1000_B02C, read_data);
if (read_data !== `SOC_NMI_RESP_RESERVED) $fatal(1, "fault detail was not recorded");
@(negedge clk_i);
sysctrl.fault_code_i = `SOC_NMI_RESP_DECERR;
fault_valid_i = 1'b1;
fault_addr_i = 32'hA000_0000;
fault_wstrb_i = 4'h0;
fault_reserved_i = 1'b0;
@(negedge clk_i);
fault_valid_i = 1'b0;
read_register(32'h1000_B014, read_data);
if (read_data !== 32'h1000_F000) $fatal(1, "later fault overwrote first fault address");
read_register(32'h1000_B018, read_data);
if (read_data !== 32'h0000_0002) $fatal(1, "later fault did not increment count");
read_register(32'h1000_B02C, read_data);
if (read_data !== `SOC_NMI_RESP_RESERVED) $fatal(1, "later fault overwrote first fault detail");
write_register(32'h1000_B010, 32'h0000_0001);
read_register(32'h1000_B010, read_data);
if (read_data !== 32'h0000_000A) $fatal(1, "fault W1C did not clear pending");
write_register(32'h1000_B040, 32'h0000_0005);
read_register(32'h1000_B044, read_data);
if (read_data !== 32'd11) $fatal(1, "performance snapshot was not recorded");
read_register(32'h1000_B020, read_data);
if (read_data !== 32'h0000_003F) $fatal(1, "user cores were not held in reset");
write_register(32'h1000_B000, 32'h0000_0006);
+56
View File
@@ -0,0 +1,56 @@
"""DMA protocol regression tests."""
from __future__ import annotations
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_dma_reports_bus_errors_and_transfers_exact_word_count(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
if iverilog is None or vvp is None:
return
source_list = tmp_path / "dma_error.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/mini/top'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"),
str(ROOT / "rtl/mini/top/soc_nmi_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/ip/native/peripheral/dma.sv"),
str(ROOT / "rtl/ip/native/peripheral/dma_core.sv"),
str(ROOT / "tests/rtl/dma_error_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "dma_error_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 / "dma_error_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "dma_error_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "dma error responder test passed" in result.stdout
+4 -1
View File
@@ -110,8 +110,9 @@ def test_bus_fault_responder_handles_reserved_and_unmapped_addresses(tmp_path: P
f"+incdir+{tmp_path / 'user_extensions' / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"),
str(ROOT / "rtl/mini/top/soc_nmi_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/ip/native/interconnect/nmi_regslice.sv"),
str(ROOT / "rtl/mini/top/soc_nmi_regslice.sv"),
str(ROOT / "rtl/mini/top/bus.sv"),
str(ROOT / "tests/rtl/bus_fault_tb.sv"),
"",
@@ -163,6 +164,7 @@ def test_sysctrl_fault_registers_record_and_clear_pending(tmp_path: Path) -> Non
f"+incdir+{ROOT / 'rtl/mini/top'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"),
str(ROOT / "rtl/mini/top/soc_nmi_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/ip/native/peripheral/pll_ctrl_if.sv"),
str(ROOT / "rtl/ip/native/peripheral/sysctrl.sv"),
@@ -211,6 +213,7 @@ def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path:
f"+incdir+{ROOT / 'rtl/mini/top'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"),
str(ROOT / "rtl/mini/top/soc_nmi_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"),
+52
View File
@@ -0,0 +1,52 @@
"""Tests for the machine-readable benchmark log parser."""
from __future__ import annotations
from scripts.parse_performance_log import parse_log
def test_parse_log_requires_terminal_marker_and_complete_samples() -> None:
report = parse_log(
"PERF region=sdram op=read words=1024 checksum=0x1234 mgmt_wait=10 "
"native_wait=9 sdram_wait=8 psram_wait=0 flash_wait=0 dma_wait=0\n"
"PERF_BENCHMARK_PASS\n"
)
assert report["status"] == "passed"
assert report["failure_marker"] is False
assert report["pass_marker"] is True
assert report["samples"] == [
{
"checksum": 0x1234,
"dma_wait": 0,
"flash_wait": 0,
"mgmt_wait": 10,
"native_wait": 9,
"operation": "read",
"psram_wait": 0,
"region": "sdram",
"sdram_wait": 8,
"words": 1024,
}
]
def test_parse_log_rejects_missing_benchmark_marker() -> None:
report = parse_log(
"PERF region=flash op=read words=1024 checksum=0 mgmt_wait=1 native_wait=1 "
"sdram_wait=0 psram_wait=0 flash_wait=1 dma_wait=0\n"
)
assert report["status"] == "failed"
def test_parse_log_rejects_report_with_performance_failure() -> None:
report = parse_log(
"PERF region=sdram op=read words=1024 checksum=0x1234 mgmt_wait=10 "
"native_wait=9 sdram_wait=8 psram_wait=0 flash_wait=0 dma_wait=0\n"
"PERF_FAIL region=sdram op=read reason=data expected=1234 actual=0\n"
"PERF_BENCHMARK_PASS\n"
)
assert report["status"] == "failed"
assert report["failure_marker"] is True
+5
View File
@@ -50,6 +50,9 @@ def test_pin_map_generates_asic_and_platform_bindings(tmp_path: Path) -> None:
testbench = (tmp_path / "rtl/retrosoc_asic_tb_bindings.svh").read_text(
encoding="utf-8"
)
verilator = (tmp_path / "rtl/retrosoc_asic_verilator_bindings.svh").read_text(
encoding="utf-8"
)
assert "inout extclk_i_pad," in ports
assert "input xi_i_pad," in ports
@@ -60,6 +63,8 @@ def test_pin_map_generates_asic_and_platform_bindings(tmp_path: Path) -> None:
assert ".gpio_15_io_pad()" in fpga
assert ".gpio_24_io_pad(s_psram_dat1)" in testbench
assert testbench.count(".gpio_24_io_pad(") == 1
assert ".sdram_clk_o_pad(s_sdram_clk)" in verilator
assert ".sdram_dq15_io_pad(s_sdram_dq[15])" in verilator
assert "user_gpio_" not in ports
assert "user_gpio_" not in pads
assert "user_gpio_" not in testbench
+23 -2
View File
@@ -112,6 +112,14 @@ def test_generate_all_is_stable_and_expands_paths(tmp_path: Path) -> None:
assert str(ROOT / "rtl/managed/clusterip") in cluster
assert (tmp_path / "core_hazard3.fl").is_file()
assert (tmp_path / "core_picorv32.fl").is_file()
assert {
"pdk_gf180.fl",
"pdk_ics55.fl",
"pdk_ics55_verilator.fl",
"pdk_ics55_yosys.fl",
"pdk_ihp130.fl",
"pdk_sky130.fl",
}.issubset({path.name for path in generated})
def test_source_export_selects_the_requested_management_core(tmp_path: Path) -> None:
@@ -196,7 +204,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
gpio_user = parse_filelists([gpio_user_filelist], require_files=False)
assert "+define+SV_ASSRT_DISABLE" in bus.defines
assert ROOT / "rtl/mini/top/bus.sv" in bus.files
assert ROOT / "rtl/ip/native/interconnect/nmi_regslice.sv" in bus.files
assert ROOT / "rtl/mini/top/soc_nmi_regslice.sv" in bus.files
assert ROOT / "rtl/mini/formal/bus_formal.sv" in bus.files
assert ROOT / "rtl/ip/native/interconnect/nmi2apb.sv" in nmi2apb.files
assert ROOT / "rtl/mini/formal/nmi2apb_formal.sv" in nmi2apb.files
@@ -612,10 +620,23 @@ def test_management_core_selection_is_limited_to_hazard3_and_picorv32() -> None:
assert "DEF_LIST += +define+CORE_$(CORE)" in makefile
assert "`ifdef CORE_PICORV32" in wrapper
assert "`elsif CORE_HAZARD3" in wrapper
assert "ahbl2nmi u_ahbl2nmi" in wrapper
assert "ahbl2soc_nmi u_ahbl2soc_nmi" in wrapper
assert ".RESET_VECTOR (`SOC_CPU_RESET_ADDR)" in wrapper
def test_benchmark_profile_uses_functional_sram_and_reserved_data() -> None:
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
profile = (ROOT / "configs/benchmark/ihp130-hazard3.mk").read_text(encoding="utf-8")
benchmark = (ROOT / "app/apps/benchmark/main.c").read_text(encoding="utf-8")
assert "PDK_BEHAV ?= NO" in makefile
assert "PDK_BEHAV HAVE_SVA" in makefile
assert "PDK_BEHAV=YES is for functional simulation" in makefile
assert "HAVE_SRAM_MACRO := YES" in profile
assert "PDK_BEHAV := YES" in profile
assert "RS_BENCHMARK_SRAM_OFFSET UINT32_C(0x10000)" in benchmark
def test_smoke_regression_uses_ihp130_behavioral_coverage_only() -> None:
commands, profiles = select_regression("smoke", "IHP130")
+141
View File
@@ -0,0 +1,141 @@
"""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 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"
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,
)
source_list = tmp_path / "sdram_data.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{generated / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/ip/native/memory/sdram.sv"),
str(ROOT / "rtl/ip/native/memory/sdram_clkgen.sv"),
str(ROOT / "rtl/ip/native/memory/sdram_reg.sv"),
str(ROOT / "rtl/ip/native/memory/sdram_core.sv"),
str(ROOT / "rtl/mini/dv/verilator/rtl/sdram_verilator_model.sv"),
str(ROOT / "tests/rtl/sdram_data_tb.sv"),
"",
]
),
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"
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,
)
source_list = tmp_path / "sdram_timing.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
"+define+SDRAM_TIMING_MODEL",
f"+incdir+{generated / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/managed/third_party/model/sdram'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/ip/native/memory/sdram.sv"),
str(ROOT / "rtl/ip/native/memory/sdram_clkgen.sv"),
str(ROOT / "rtl/ip/native/memory/sdram_reg.sv"),
str(ROOT / "rtl/ip/native/memory/sdram_core.sv"),
str(ROOT / "tests/rtl/sdram_data_tb.sv"),
"",
]
),
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
+6
View File
@@ -202,6 +202,12 @@ def test_ics55_sim_model_preparer_patches_every_h7cr_muxi2_variant(tmp_path: Pat
assert first.returncode == 0, first.stderr
prepared = output.read_text(encoding="utf-8")
assert prepared.startswith(
"/* verilator lint_off DECLFILENAME */\n/* verilator lint_off SPECIFYIGN */\n"
)
assert prepared.endswith(
"/* verilator lint_on SPECIFYIGN */\n/* verilator lint_on DECLFILENAME */\n"
)
assert prepared.count("wire muxi2_y;") == len(cells)
assert prepared.count("udp_mux2 u0(muxi2_y, A, B, S0);") == len(cells)
assert "not u1(Y, Y);" not in prepared