mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
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:
61 files changed
+2539
-433
No files matched your search
+18
-10
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user