mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- Introduced new task in for handling high-performance APU writes with access fault checks. - Updated to support an expanded resource count, including ownership and IRQ routing for the new APU resource. - Enhanced to validate IRQ expectations for the newly added APU resource. - Created for directed verification of APU-P1 APB4 register shell and integrated IRQ ownership topology. - Added to ensure synchronization between RTL and SDK register ABI. - Modified to parameterize tests for product modes, improving flexibility in testing. - Updated to reflect changes in APU memory mapping and ensure correct assertions. - Enhanced to validate the complete IRQ and resource allocations for the APU.
400 lines
14 KiB
Systemverilog
400 lines
14 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
|
|
`include "axi4_define.svh"
|
|
`include "rib_defs.svh"
|
|
|
|
module axi4_interconnect_tb;
|
|
localparam int NumMasters = 8;
|
|
localparam int NumTargets = 9;
|
|
|
|
logic clk_i = 1'b0;
|
|
logic rst_n_i = 1'b0;
|
|
logic fault_valid_o;
|
|
logic [31:0] fault_addr_o;
|
|
logic [ 3:0] fault_wstrb_o;
|
|
logic fault_reserved_o;
|
|
logic fault_access_o;
|
|
logic [ 2:0] fault_master_o;
|
|
logic [ 2:0] fault_code_o;
|
|
logic user_bus_idle_o;
|
|
|
|
axi4_if #(
|
|
.ADDR_WIDTH(32),
|
|
.DATA_WIDTH(32),
|
|
.ID_WIDTH (1),
|
|
.USER_WIDTH(1)
|
|
) masters[NumMasters] (
|
|
.aclk (clk_i),
|
|
.aresetn(rst_n_i)
|
|
);
|
|
|
|
axi4_if #(
|
|
.ADDR_WIDTH(32),
|
|
.DATA_WIDTH(32),
|
|
.ID_WIDTH (1),
|
|
.USER_WIDTH(1)
|
|
) targets[NumTargets] (
|
|
.aclk (clk_i),
|
|
.aresetn(rst_n_i)
|
|
);
|
|
|
|
always #5 clk_i = ~clk_i;
|
|
|
|
axi4_interconnect #(
|
|
.NumMasters(NumMasters),
|
|
.NumTargets(NumTargets)
|
|
) u_dut (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.masters (masters),
|
|
.targets (targets),
|
|
.user_bus_enable_i (1'b1),
|
|
.user_bus_idle_o (user_bus_idle_o),
|
|
.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_code_o (fault_code_o),
|
|
.perf_mgmt_wait_o (),
|
|
.perf_user_wait_o (),
|
|
.perf_dma_wait_o (),
|
|
.perf_sdio0_wait_o (),
|
|
.perf_sdio1_wait_o (),
|
|
.perf_usb2_wait_o (),
|
|
.perf_apb4_periph_wait_o(),
|
|
.perf_apb4_system_wait_o(),
|
|
.perf_sdram_wait_o (),
|
|
.perf_psram_wait_o (),
|
|
.perf_flash_wait_o (),
|
|
.perf_opipsram_wait_o ()
|
|
);
|
|
|
|
for (genvar target = 0; target < NumTargets; target++) begin : GEN_TARGETS
|
|
localparam logic [1:0] Response =
|
|
(target == 7) ? `AXI4_RESP_DECODE_ERROR :
|
|
(target == 8) ? `AXI4_RESP_SLAVE_ERROR : `AXI4_RESP_OKAY;
|
|
axi4_error_slave #(
|
|
.Response(Response)
|
|
) u_target (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.axi4 (targets[target])
|
|
);
|
|
end
|
|
|
|
`define INIT_MASTER(index) \
|
|
masters[index].awid = '0; \
|
|
masters[index].awaddr = '0; \
|
|
masters[index].awlen = '0; \
|
|
masters[index].awsize = `AXI4_BURST_SIZE_4BYTES; \
|
|
masters[index].awburst = `AXI4_BURST_TYPE_INCR; \
|
|
masters[index].awlock = `AXI4_LOCK_NORM; \
|
|
masters[index].awcache = `AXI4_CACHE_NO_BUF; \
|
|
masters[index].awprot = `AXI4_PROT_DATA; \
|
|
masters[index].awqos = `AXI4_QOS_NORMAL; \
|
|
masters[index].awregion = `AXI4_REGION_NORMAL; \
|
|
masters[index].awuser = '0; \
|
|
masters[index].awvalid = 1'b0; \
|
|
masters[index].wdata = '0; \
|
|
masters[index].wstrb = '0; \
|
|
masters[index].wlast = 1'b0; \
|
|
masters[index].wuser = '0; \
|
|
masters[index].wvalid = 1'b0; \
|
|
masters[index].bready = 1'b0; \
|
|
masters[index].arid = '0; \
|
|
masters[index].araddr = '0; \
|
|
masters[index].arlen = '0; \
|
|
masters[index].arsize = `AXI4_BURST_SIZE_4BYTES; \
|
|
masters[index].arburst = `AXI4_BURST_TYPE_INCR; \
|
|
masters[index].arlock = `AXI4_LOCK_NORM; \
|
|
masters[index].arcache = `AXI4_CACHE_NO_BUF; \
|
|
masters[index].arprot = `AXI4_PROT_DATA; \
|
|
masters[index].arqos = `AXI4_QOS_NORMAL; \
|
|
masters[index].arregion = `AXI4_REGION_NORMAL; \
|
|
masters[index].aruser = '0; \
|
|
masters[index].arvalid = 1'b0; \
|
|
masters[index].rready = 1'b0;
|
|
|
|
task automatic issue_mgmt_error_read(input logic [31:0] address, input logic [7:0] length,
|
|
input logic [1:0] response, input logic [2:0] fault_code);
|
|
integer beat;
|
|
begin
|
|
@(negedge clk_i);
|
|
masters[0].araddr = address;
|
|
masters[0].arlen = length;
|
|
masters[0].arvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[0].arready);
|
|
@(negedge clk_i);
|
|
masters[0].arvalid = 1'b0;
|
|
masters[0].rready = 1'b1;
|
|
beat = 0;
|
|
while (beat <= length) begin
|
|
@(negedge clk_i);
|
|
if (masters[0].rvalid) begin
|
|
if ((masters[0].rresp != response) || (masters[0].rlast != (beat == int'(length)))) begin
|
|
$fatal(1, "management error response mismatch on beat %0d", beat);
|
|
end
|
|
if ((beat == int'(length)) &&
|
|
(!fault_valid_o || (fault_addr_o != address) || fault_access_o ||
|
|
(fault_master_o != 3'd0) || (fault_code_o != fault_code))) begin
|
|
$fatal(1, "management fault classification mismatch");
|
|
end
|
|
beat = beat + 1;
|
|
end
|
|
end
|
|
@(negedge clk_i);
|
|
masters[0].rready = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic issue_denied_user_write(input logic [31:0] address);
|
|
begin
|
|
@(negedge clk_i);
|
|
masters[1].awaddr = address;
|
|
masters[1].awlen = 8'd0;
|
|
masters[1].awvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[1].awready);
|
|
@(negedge clk_i);
|
|
masters[1].awvalid = 1'b0;
|
|
masters[1].wdata = 32'hA5A5_5A5A;
|
|
masters[1].wstrb = 4'hF;
|
|
masters[1].wlast = 1'b1;
|
|
masters[1].wvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[1].wready);
|
|
@(negedge clk_i);
|
|
masters[1].wvalid = 1'b0;
|
|
while (!masters[1].bvalid) @(negedge clk_i);
|
|
masters[1].bready = 1'b1;
|
|
#1;
|
|
if ((masters[1].bresp != `AXI4_RESP_SLAVE_ERROR) || !fault_valid_o ||
|
|
!fault_access_o || (fault_addr_o != address) || (fault_wstrb_o != 4'hF) ||
|
|
(fault_master_o != 3'd1) || (fault_code_o != `RIB_RESP_PROTERR)) begin
|
|
$fatal(1, "user access fault classification mismatch");
|
|
end
|
|
@(negedge clk_i);
|
|
masters[1].bready = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic issue_hp_apu_write(input logic [31:0] address, input logic [1:0] expected_response,
|
|
input logic expected_access_fault);
|
|
begin
|
|
@(negedge clk_i);
|
|
masters[6].awaddr = address;
|
|
masters[6].awlen = 8'd0;
|
|
masters[6].awvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[6].awready);
|
|
@(negedge clk_i);
|
|
masters[6].awvalid = 1'b0;
|
|
masters[6].wdata = 32'h1234_5678;
|
|
masters[6].wstrb = 4'hf;
|
|
masters[6].wlast = 1'b1;
|
|
masters[6].wvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[6].wready);
|
|
@(negedge clk_i);
|
|
masters[6].wvalid = 1'b0;
|
|
masters[6].bready = 1'b1;
|
|
while (!masters[6].bvalid) @(negedge clk_i);
|
|
#1;
|
|
if ((masters[6].bresp != expected_response) ||
|
|
(fault_valid_o != expected_access_fault) ||
|
|
(expected_access_fault &&
|
|
(!fault_access_o || (fault_addr_o != address) || (fault_master_o != 3'd6) ||
|
|
(fault_code_o != `RIB_RESP_PROTERR)))) begin
|
|
$fatal(
|
|
1,
|
|
"HP APU access policy mismatch at %h: resp=%0d fault=%0d access=%0d master=%0d code=%0d",
|
|
address, masters[6].bresp, fault_valid_o, fault_access_o, fault_master_o, fault_code_o);
|
|
end
|
|
@(negedge clk_i);
|
|
masters[6].bready = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic issue_management_with_idle_sdio;
|
|
integer cycles;
|
|
begin
|
|
@(negedge clk_i);
|
|
masters[0].araddr = 32'h0000_0000;
|
|
masters[0].arlen = 8'd0;
|
|
masters[0].arvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[0].arready);
|
|
@(negedge clk_i);
|
|
masters[0].arvalid = 1'b0;
|
|
masters[0].rready = 1'b1;
|
|
cycles = 0;
|
|
while (!masters[0].rvalid && cycles < 100) begin
|
|
if (masters[3].arvalid || masters[3].awvalid || masters[3].wvalid ||
|
|
masters[4].arvalid || masters[4].awvalid || masters[4].wvalid ||
|
|
masters[5].arvalid || masters[5].awvalid || masters[5].wvalid ||
|
|
masters[6].arvalid || masters[6].awvalid || masters[6].wvalid) begin
|
|
$fatal(1, "inactive storage master drove a request during management boot traffic");
|
|
end
|
|
@(negedge clk_i);
|
|
cycles = cycles + 1;
|
|
end
|
|
if (cycles >= 100) $fatal(1, "idle SDIO masters blocked management boot traffic");
|
|
if (masters[0].rresp != `AXI4_RESP_OKAY) begin
|
|
$fatal(1, "management boot traffic received an unexpected response");
|
|
end
|
|
@(posedge clk_i);
|
|
@(negedge clk_i);
|
|
masters[0].rready = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic issue_contending_sdio_faults;
|
|
integer cycles;
|
|
begin
|
|
@(negedge clk_i);
|
|
masters[3].araddr = 32'hA000_1000;
|
|
masters[3].arlen = 8'd0;
|
|
masters[3].arvalid = 1'b1;
|
|
masters[4].araddr = 32'hA000_2000;
|
|
masters[4].arlen = 8'd0;
|
|
masters[4].arvalid = 1'b1;
|
|
do @(posedge clk_i); while (!(masters[3].arready && masters[4].arready));
|
|
@(negedge clk_i);
|
|
masters[3].arvalid = 1'b0;
|
|
masters[4].arvalid = 1'b0;
|
|
cycles = 0;
|
|
while (!masters[3].rvalid && !masters[4].rvalid && cycles < 100) begin
|
|
@(negedge clk_i);
|
|
cycles = cycles + 1;
|
|
end
|
|
if (cycles >= 100) $fatal(1, "SDIO master contention did not produce a response");
|
|
if (masters[3].rvalid) begin
|
|
masters[3].rready = 1'b1;
|
|
#1;
|
|
if ((masters[3].rresp != `AXI4_RESP_DECODE_ERROR) || !fault_valid_o ||
|
|
(fault_master_o != 3'd3) || (fault_addr_o != 32'hA000_1000) ||
|
|
(fault_code_o != `RIB_RESP_DECERR)) begin
|
|
$fatal(1, "SDIO0 fault attribution mismatch");
|
|
end
|
|
@(posedge clk_i);
|
|
@(negedge clk_i);
|
|
masters[3].rready = 1'b0;
|
|
end else begin
|
|
masters[4].rready = 1'b1;
|
|
#1;
|
|
if ((masters[4].rresp != `AXI4_RESP_DECODE_ERROR) || !fault_valid_o ||
|
|
(fault_master_o != 3'd4) || (fault_addr_o != 32'hA000_2000) ||
|
|
(fault_code_o != `RIB_RESP_DECERR)) begin
|
|
$fatal(1, "SDIO1 fault attribution mismatch");
|
|
end
|
|
@(posedge clk_i);
|
|
@(negedge clk_i);
|
|
masters[4].rready = 1'b0;
|
|
end
|
|
|
|
cycles = 0;
|
|
while (!masters[3].rvalid && !masters[4].rvalid && cycles < 100) begin
|
|
@(negedge clk_i);
|
|
cycles = cycles + 1;
|
|
end
|
|
if (cycles >= 100) $fatal(1, "second SDIO master response was lost");
|
|
if (masters[3].rvalid) begin
|
|
masters[3].rready = 1'b1;
|
|
#1;
|
|
if ((masters[3].rresp != `AXI4_RESP_DECODE_ERROR) || !fault_valid_o ||
|
|
(fault_master_o != 3'd3) || (fault_addr_o != 32'hA000_1000) ||
|
|
(fault_code_o != `RIB_RESP_DECERR)) begin
|
|
$fatal(1, "second SDIO0 fault attribution mismatch");
|
|
end
|
|
@(posedge clk_i);
|
|
@(negedge clk_i);
|
|
masters[3].rready = 1'b0;
|
|
end else begin
|
|
masters[4].rready = 1'b1;
|
|
#1;
|
|
if ((masters[4].rresp != `AXI4_RESP_DECODE_ERROR) || !fault_valid_o ||
|
|
(fault_master_o != 3'd4) || (fault_addr_o != 32'hA000_2000) ||
|
|
(fault_code_o != `RIB_RESP_DECERR)) begin
|
|
$fatal(1, "second SDIO1 fault attribution mismatch");
|
|
end
|
|
@(posedge clk_i);
|
|
@(negedge clk_i);
|
|
masters[4].rready = 1'b0;
|
|
end
|
|
end
|
|
endtask
|
|
|
|
task automatic issue_hp_accesses;
|
|
integer beat;
|
|
begin
|
|
@(negedge clk_i);
|
|
masters[7].araddr = 32'h3800_0000;
|
|
masters[7].arlen = 8'd15;
|
|
masters[7].arvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[7].arready);
|
|
@(negedge clk_i);
|
|
masters[7].arvalid = 1'b0;
|
|
masters[7].rready = 1'b1;
|
|
beat = 0;
|
|
while (beat < 16) begin
|
|
@(negedge clk_i);
|
|
if (masters[7].rvalid) begin
|
|
if ((masters[7].rresp != `AXI4_RESP_OKAY) ||
|
|
(masters[7].rlast != (beat == 15)) || fault_valid_o) begin
|
|
$fatal(1, "HP SDRAM burst was rejected or misclassified");
|
|
end
|
|
beat = beat + 1;
|
|
end
|
|
end
|
|
@(negedge clk_i);
|
|
masters[7].rready = 1'b0;
|
|
masters[7].araddr = 32'hA000_7000;
|
|
masters[7].arlen = 8'd0;
|
|
masters[7].arvalid = 1'b1;
|
|
do @(posedge clk_i); while (!masters[7].arready);
|
|
@(negedge clk_i);
|
|
masters[7].arvalid = 1'b0;
|
|
masters[7].rready = 1'b1;
|
|
while (!masters[7].rvalid) @(negedge clk_i);
|
|
#1;
|
|
if ((masters[7].rresp != `AXI4_RESP_DECODE_ERROR) || !fault_valid_o ||
|
|
(fault_master_o != 3'd7) || (fault_addr_o != 32'hA000_7000) ||
|
|
(fault_code_o != `RIB_RESP_DECERR)) begin
|
|
$fatal(1, "HP decode fault attribution mismatch");
|
|
end
|
|
@(posedge clk_i);
|
|
@(negedge clk_i);
|
|
masters[7].rready = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
initial begin
|
|
`INIT_MASTER(0)
|
|
`INIT_MASTER(1)
|
|
`INIT_MASTER(2)
|
|
`INIT_MASTER(3)
|
|
`INIT_MASTER(4)
|
|
`INIT_MASTER(5)
|
|
`INIT_MASTER(6)
|
|
`INIT_MASTER(7)
|
|
repeat (4) @(posedge clk_i);
|
|
rst_n_i = 1'b1;
|
|
|
|
issue_management_with_idle_sdio();
|
|
issue_mgmt_error_read(32'hA000_0000, 8'd0, `AXI4_RESP_DECODE_ERROR, `RIB_RESP_DECERR);
|
|
issue_mgmt_error_read(32'h3000_0000, 8'd16, `AXI4_RESP_SLAVE_ERROR, `RIB_RESP_BURSTERR);
|
|
`ifdef MINI_PRODUCT
|
|
issue_hp_apu_write(32'h1001_301C, `AXI4_RESP_OKAY, 1'b0);
|
|
issue_hp_apu_write(32'h1001_3040, `AXI4_RESP_SLAVE_ERROR, 1'b1);
|
|
`else
|
|
issue_denied_user_write(32'h1000_B000);
|
|
`endif
|
|
issue_contending_sdio_faults();
|
|
issue_hp_accesses();
|
|
|
|
$display("AXI4 interconnect fault classification test passed");
|
|
$finish;
|
|
end
|
|
|
|
`undef INIT_MASTER
|
|
endmodule
|