mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
feat: add AXI4 interconnect testbench and enhance existing tests
- Introduced a new testbench for the AXI4 interconnect () to validate fault classification for decode and access errors. - Updated and to reflect changes in bus naming conventions. - Enhanced to include AXI4-Stream interface checks and validate stream data transfers. - Modified to integrate AXI4-Stream interfaces for improved DMA testing. - Added new Python tests () to verify AXI4 to RIBP burst bridge functionality and interconnect fault classification. - Updated existing tests to include AXI4 interfaces and ensure proper error handling and response validation. - Adjusted memory map generation and test setups to accommodate new AXI4 interface requirements.
This commit is contained in:
65 files changed
+4271
-649
No files matched your search
@@ -0,0 +1,263 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "axi4_define.svh"
|
||||
|
||||
module axi42ribp_burst_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic [31:0] memory [0:63];
|
||||
logic [31:0] expected;
|
||||
integer target_accesses = 0;
|
||||
integer error_beats;
|
||||
integer cycle_count = 0;
|
||||
integer burst_cycles;
|
||||
integer single_cycles;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) axi4 (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
ribp_if ribp ();
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
always @(posedge clk_i) cycle_count <= cycle_count + 1;
|
||||
|
||||
axi42ribp_burst u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.axi4 (axi4),
|
||||
.ribp (ribp)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
ribp.ready <= 1'b0;
|
||||
ribp.rdata <= '0;
|
||||
target_accesses <= 0;
|
||||
end else begin
|
||||
ribp.ready <= ribp.valid && !ribp.ready;
|
||||
if (ribp.valid && !ribp.ready) begin
|
||||
target_accesses <= target_accesses + 1;
|
||||
ribp.rdata <= memory[ribp.addr[7:2]];
|
||||
for (int lane = 0; lane < 4; lane++) begin
|
||||
if (ribp.wstrb[lane]) begin
|
||||
memory[ribp.addr[7:2]][lane*8+:8] <= ribp.wdata[lane*8+:8];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign ribp.resp_err = 1'b0;
|
||||
|
||||
task automatic init_axi4;
|
||||
begin
|
||||
axi4.awid = '0;
|
||||
axi4.awaddr = '0;
|
||||
axi4.awlen = '0;
|
||||
axi4.awsize = `AXI4_BURST_SIZE_4BYTES;
|
||||
axi4.awburst = `AXI4_BURST_TYPE_INCR;
|
||||
axi4.awlock = `AXI4_LOCK_NORM;
|
||||
axi4.awcache = `AXI4_CACHE_NO_BUF;
|
||||
axi4.awprot = `AXI4_PROT_DATA;
|
||||
axi4.awqos = `AXI4_QOS_NORMAL;
|
||||
axi4.awregion = `AXI4_REGION_NORMAL;
|
||||
axi4.awuser = '0;
|
||||
axi4.awvalid = 1'b0;
|
||||
axi4.wdata = '0;
|
||||
axi4.wstrb = '0;
|
||||
axi4.wlast = 1'b0;
|
||||
axi4.wuser = '0;
|
||||
axi4.wvalid = 1'b0;
|
||||
axi4.bready = 1'b0;
|
||||
axi4.arid = '0;
|
||||
axi4.araddr = '0;
|
||||
axi4.arlen = '0;
|
||||
axi4.arsize = `AXI4_BURST_SIZE_4BYTES;
|
||||
axi4.arburst = `AXI4_BURST_TYPE_INCR;
|
||||
axi4.arlock = `AXI4_LOCK_NORM;
|
||||
axi4.arcache = `AXI4_CACHE_NO_BUF;
|
||||
axi4.arprot = `AXI4_PROT_DATA;
|
||||
axi4.arqos = `AXI4_QOS_NORMAL;
|
||||
axi4.arregion = `AXI4_REGION_NORMAL;
|
||||
axi4.aruser = '0;
|
||||
axi4.arvalid = 1'b0;
|
||||
axi4.rready = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic issue_write4(input logic [31:0] address);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
axi4.awaddr = address;
|
||||
axi4.awlen = 8'd3;
|
||||
axi4.awvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.awready);
|
||||
@(negedge clk_i);
|
||||
axi4.awvalid = 1'b0;
|
||||
for (int beat = 0; beat < 4; beat++) begin
|
||||
axi4.wdata = 32'hA500_0000 + beat;
|
||||
axi4.wstrb = 4'hF;
|
||||
axi4.wlast = beat == 3;
|
||||
axi4.wvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.wready);
|
||||
@(negedge clk_i);
|
||||
axi4.wvalid = 1'b0;
|
||||
end
|
||||
repeat (2) @(posedge clk_i);
|
||||
axi4.bready = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.bvalid);
|
||||
if (axi4.bresp != `AXI4_RESP_OKAY) $fatal(1, "write burst returned an error");
|
||||
@(negedge clk_i);
|
||||
axi4.bready = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic issue_read4(input logic [31:0] address);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
axi4.araddr = address;
|
||||
axi4.arlen = 8'd3;
|
||||
axi4.arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.arready);
|
||||
@(negedge clk_i);
|
||||
axi4.arvalid = 1'b0;
|
||||
for (int beat = 0; beat < 4; beat++) begin
|
||||
if (beat == 1) begin
|
||||
repeat (3) @(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
end
|
||||
axi4.rready = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.rvalid);
|
||||
expected = 32'hA500_0000 + beat;
|
||||
if (axi4.rdata != expected || axi4.rresp != `AXI4_RESP_OKAY ||
|
||||
axi4.rlast != (beat == 3)) begin
|
||||
$fatal(1, "read beat %0d mismatch: data=%08x expected=%08x resp=%0d last=%0d", beat,
|
||||
axi4.rdata, expected, axi4.rresp, axi4.rlast);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
axi4.rready = 1'b0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic issue_illegal_read(input logic [31:0] address);
|
||||
integer accesses_before;
|
||||
begin
|
||||
accesses_before = target_accesses;
|
||||
@(negedge clk_i);
|
||||
axi4.araddr = address;
|
||||
axi4.arlen = 8'd16;
|
||||
axi4.arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.arready);
|
||||
@(negedge clk_i);
|
||||
axi4.arvalid = 1'b0;
|
||||
axi4.rready = 1'b1;
|
||||
error_beats = 0;
|
||||
while (error_beats < 17) begin
|
||||
@(posedge clk_i);
|
||||
if (axi4.rvalid) begin
|
||||
if (axi4.rresp != `AXI4_RESP_SLAVE_ERROR || axi4.rlast != (error_beats == 16)) begin
|
||||
$fatal(1, "illegal burst response mismatch");
|
||||
end
|
||||
error_beats = error_beats + 1;
|
||||
end
|
||||
end
|
||||
@(negedge clk_i);
|
||||
axi4.rready = 1'b0;
|
||||
if (target_accesses != accesses_before) begin
|
||||
$fatal(1, "illegal burst reached the RIBP target");
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic issue_early_last_write(input logic [31:0] address);
|
||||
integer accesses_before;
|
||||
begin
|
||||
accesses_before = target_accesses;
|
||||
@(negedge clk_i);
|
||||
axi4.awaddr = address;
|
||||
axi4.awlen = 8'd3;
|
||||
axi4.awvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.awready);
|
||||
@(negedge clk_i);
|
||||
axi4.awvalid = 1'b0;
|
||||
axi4.wdata = 32'hDEAD_BEEF;
|
||||
axi4.wstrb = 4'hF;
|
||||
axi4.wlast = 1'b1;
|
||||
axi4.wvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.wready);
|
||||
@(negedge clk_i);
|
||||
axi4.wvalid = 1'b0;
|
||||
axi4.bready = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.bvalid);
|
||||
if (axi4.bresp != `AXI4_RESP_SLAVE_ERROR) begin
|
||||
$fatal(1, "early WLAST did not return SLVERR");
|
||||
end
|
||||
@(negedge clk_i);
|
||||
axi4.bready = 1'b0;
|
||||
axi4.wlast = 1'b0;
|
||||
if (target_accesses != accesses_before + 1) begin
|
||||
$fatal(1, "early WLAST must commit exactly one RIBP beat");
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic issue_read(input logic [31:0] address, input logic [7:0] length);
|
||||
integer beat;
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
axi4.araddr = address;
|
||||
axi4.arlen = length;
|
||||
axi4.arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.arready);
|
||||
@(negedge clk_i);
|
||||
axi4.arvalid = 1'b0;
|
||||
axi4.rready = 1'b1;
|
||||
beat = 0;
|
||||
while (beat <= length) begin
|
||||
@(posedge clk_i);
|
||||
if (axi4.rvalid) begin
|
||||
if (axi4.rresp != `AXI4_RESP_OKAY || axi4.rlast != (beat == length)) begin
|
||||
$fatal(1, "performance read response mismatch");
|
||||
end
|
||||
beat = beat + 1;
|
||||
end
|
||||
end
|
||||
@(negedge clk_i);
|
||||
axi4.rready = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
init_axi4();
|
||||
for (int index = 0; index < 64; index++) memory[index] = '0;
|
||||
repeat (4) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
issue_write4(32'h0000_0040);
|
||||
issue_read4(32'h0000_0040);
|
||||
issue_illegal_read(32'h0000_0080);
|
||||
issue_early_last_write(32'h0000_00C0);
|
||||
burst_cycles = cycle_count;
|
||||
issue_read(32'h0000_0000, 8'd15);
|
||||
burst_cycles = cycle_count - burst_cycles;
|
||||
single_cycles = cycle_count;
|
||||
for (int index = 0; index < 16; index++) begin
|
||||
issue_read(32'(index * 4), 8'd0);
|
||||
end
|
||||
single_cycles = cycle_count - single_cycles;
|
||||
if ((burst_cycles * 5) > (single_cycles * 4)) begin
|
||||
$fatal(1, "16-beat burst improvement is below 20%%: burst=%0d single=%0d", burst_cycles,
|
||||
single_cycles);
|
||||
end
|
||||
if (target_accesses != 41) $fatal(1, "unexpected RIBP access count");
|
||||
$display("AXI4 to RIBP burst bridge test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,195 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "axi4_define.svh"
|
||||
`include "rib_defs.svh"
|
||||
|
||||
module axi4_interconnect_tb;
|
||||
localparam int NUM_MASTERS = 3;
|
||||
localparam int NUM_TARGETS = 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 [ 1: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[NUM_MASTERS] (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) targets[NUM_TARGETS] (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
axi4_interconnect #(
|
||||
.NUM_MASTERS(NUM_MASTERS),
|
||||
.NUM_TARGETS(NUM_TARGETS)
|
||||
) 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_ribp_wait_o (),
|
||||
.perf_apb_wait_o (),
|
||||
.perf_sdram_wait_o(),
|
||||
.perf_psram_wait_o(),
|
||||
.perf_flash_wait_o()
|
||||
);
|
||||
|
||||
for (genvar target = 0; target < NUM_TARGETS; 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 != 2'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 != 2'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
|
||||
|
||||
initial begin
|
||||
`INIT_MASTER(0)
|
||||
`INIT_MASTER(1)
|
||||
`INIT_MASTER(2)
|
||||
repeat (4) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
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);
|
||||
issue_denied_user_write(32'h1000_B000);
|
||||
|
||||
$display("AXI4 interconnect fault classification test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
`undef INIT_MASTER
|
||||
endmodule
|
||||
@@ -36,7 +36,7 @@ module bus_fault_tb;
|
||||
assign apb_rib.rsp_beat = '0;
|
||||
assign apb_rib.rsp_last = 1'b1;
|
||||
|
||||
bus u_bus (
|
||||
rib_bus u_bus (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.mgmt_ribp (mgmt_ribp),
|
||||
|
||||
+86
-10
@@ -27,6 +27,10 @@ module dma_error_tb;
|
||||
integer incr4_write_count = 0;
|
||||
integer legacy_cycles;
|
||||
integer burst_cycles;
|
||||
integer stream_tx_count = 0;
|
||||
integer stream_rx_count = 0;
|
||||
logic stream_tx_ready = 1'b0;
|
||||
logic stream_rx_valid = 1'b0;
|
||||
logic [ 1:0] model_state_q = MODEL_IDLE;
|
||||
logic [ 1:0] model_len_q = '0;
|
||||
logic [ 1:0] model_beat_q = '0;
|
||||
@@ -34,17 +38,59 @@ module dma_error_tb;
|
||||
logic model_error_q = 1'b0;
|
||||
dma_hw_trg_if hw_trg ();
|
||||
rib_if rib ();
|
||||
axi4_stream_if i2s_tx_axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_stream_if i2s_rx_axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_stream_if dvp_rx_axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
assign rib.cmd_ready = model_state_q == MODEL_IDLE;
|
||||
assign rib.w_ready = model_state_q == MODEL_WDATA;
|
||||
assign rib.rsp_valid = model_state_q == MODEL_RESP;
|
||||
assign rib.rdata = 32'hA5A5_5A5A + model_beat_q;
|
||||
assign rib.resp_err = model_error_q;
|
||||
assign rib.resp_code = model_error_q ? `RIB_RESP_DECERR : `RIB_RESP_OK;
|
||||
assign rib.rsp_beat = model_beat_q;
|
||||
assign rib.rsp_last = model_write_q || model_error_q || (model_beat_q == model_len_q);
|
||||
assign rib.cmd_ready = model_state_q == MODEL_IDLE;
|
||||
assign rib.w_ready = model_state_q == MODEL_WDATA;
|
||||
assign rib.rsp_valid = model_state_q == MODEL_RESP;
|
||||
assign rib.rdata = 32'hA5A5_5A5A + model_beat_q;
|
||||
assign rib.resp_err = model_error_q;
|
||||
assign rib.resp_code = model_error_q ? `RIB_RESP_DECERR : `RIB_RESP_OK;
|
||||
assign rib.rsp_beat = model_beat_q;
|
||||
assign rib.rsp_last = model_write_q || model_error_q || (model_beat_q == model_len_q);
|
||||
assign i2s_tx_axis.tready = stream_tx_ready;
|
||||
assign i2s_rx_axis.tdata = 32'h5100_0000 + stream_rx_count;
|
||||
assign i2s_rx_axis.tkeep = '1;
|
||||
assign i2s_rx_axis.tstrb = '1;
|
||||
assign i2s_rx_axis.tlast = stream_rx_count == 1;
|
||||
assign i2s_rx_axis.tid = '0;
|
||||
assign i2s_rx_axis.tdest = '0;
|
||||
assign i2s_rx_axis.tuser = '0;
|
||||
assign i2s_rx_axis.tvalid = stream_rx_valid;
|
||||
assign dvp_rx_axis.tdata = '0;
|
||||
assign dvp_rx_axis.tkeep = '0;
|
||||
assign dvp_rx_axis.tstrb = '0;
|
||||
assign dvp_rx_axis.tlast = 1'b0;
|
||||
assign dvp_rx_axis.tid = '0;
|
||||
assign dvp_rx_axis.tdest = '0;
|
||||
assign dvp_rx_axis.tuser = '0;
|
||||
assign dvp_rx_axis.tvalid = 1'b0;
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (i2s_tx_axis.tvalid && i2s_tx_axis.tready) begin
|
||||
if (i2s_tx_axis.tdata !== 32'hA5A5_5A5A) begin
|
||||
$fatal(1, "I2S TX stream data mismatch");
|
||||
end
|
||||
stream_tx_count <= stream_tx_count + 1;
|
||||
end
|
||||
if (i2s_rx_axis.tvalid && i2s_rx_axis.tready) begin
|
||||
stream_rx_count <= stream_rx_count + 1;
|
||||
if (stream_rx_count == 1) stream_rx_valid <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
@@ -114,7 +160,10 @@ module dma_error_tb;
|
||||
.error_addr_o(error_addr_o),
|
||||
.fsm_o (fsm_o),
|
||||
.hw_trg (hw_trg),
|
||||
.rib (rib)
|
||||
.rib (rib),
|
||||
.i2s_tx_axis (i2s_tx_axis),
|
||||
.i2s_rx_axis (i2s_rx_axis),
|
||||
.dvp_rx_axis (dvp_rx_axis)
|
||||
);
|
||||
|
||||
task automatic start_transfer;
|
||||
@@ -193,7 +242,34 @@ module dma_error_tb;
|
||||
$fatal(1, "DMA did not fall back to INCR1 for a register window");
|
||||
end
|
||||
|
||||
$display("dma error and burst performance test passed");
|
||||
mode_i = 4'd1;
|
||||
srcaddr_i = 32'h3800_2000;
|
||||
srcincr_i = 1'b1;
|
||||
xferlen_i = 32'd2;
|
||||
stream_tx_ready = 1'b0;
|
||||
start_transfer();
|
||||
repeat (3) @(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
stream_tx_ready = 1'b1;
|
||||
wait (done_o);
|
||||
@(negedge clk_i);
|
||||
if (stream_tx_count != 2) begin
|
||||
$fatal(1, "I2S TX stream transferred %0d words", stream_tx_count);
|
||||
end
|
||||
|
||||
mode_i = 4'd2;
|
||||
dstaddr_i = 32'h4000_2000;
|
||||
dstincr_i = 1'b1;
|
||||
xferlen_i = 32'd2;
|
||||
stream_rx_valid = 1'b1;
|
||||
start_transfer();
|
||||
wait (done_o);
|
||||
@(negedge clk_i);
|
||||
if (stream_rx_count != 2) begin
|
||||
$fatal(1, "I2S RX stream transferred %0d words", stream_rx_count);
|
||||
end
|
||||
|
||||
$display("dma error, burst performance, and AXI4-Stream test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -66,7 +66,7 @@ module rib_bus_tb;
|
||||
assign apb_rib.rsp_beat = '0;
|
||||
assign apb_rib.rsp_last = 1'b1;
|
||||
|
||||
bus u_bus (
|
||||
rib_bus u_bus (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.mgmt_ribp (mgmt_ribp),
|
||||
|
||||
@@ -141,8 +141,8 @@ module ribp_topology_tb;
|
||||
|
||||
expect_route(`SOC_ADDR_RIBP_GPIO_BASE, 1, 32'h1111_1111);
|
||||
expect_route(`SOC_ADDR_RIBP_GPIO_ADMIN_BASE, 1, 32'h1111_1111);
|
||||
expect_route(`SOC_ADDR_PSRAM_BASE, 4, 32'h4444_4444);
|
||||
expect_route(`SOC_ADDR_FLASH_BASE, 9, 32'h9999_9999);
|
||||
expect_route(`SOC_ADDR_RIBP_PSRAM_BASE, 4, 32'h4444_4444);
|
||||
expect_route(`SOC_ADDR_RIBP_XPI_BASE, 9, 32'h9999_9999);
|
||||
expect_route(`SOC_ADDR_RIBP_I2C1_BASE, 17, 32'h1234_5678);
|
||||
expect_disabled(`SOC_ADDR_RIBP_SDIO_BASE);
|
||||
u_gpio_ribp_if.resp_err = 1'b1;
|
||||
|
||||
+46
-14
@@ -46,6 +46,18 @@ module ws2812_dma_tb;
|
||||
rib_if dma_rib ();
|
||||
ribp_if ws_ribp ();
|
||||
ws2812_if ws2812 ();
|
||||
axi4_stream_if i2s_tx_axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_stream_if i2s_rx_axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_stream_if dvp_rx_axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
@@ -54,20 +66,37 @@ module ws2812_dma_tb;
|
||||
$fatal(1, "WS2812 DMA integration test timeout");
|
||||
end
|
||||
|
||||
assign ws_ribp.valid = host_active ? host_valid : dma_ws_valid;
|
||||
assign ws_ribp.addr = host_active ? host_addr : bus_addr_q;
|
||||
assign ws_ribp.wdata = host_active ? host_wdata : dma_rib.wdata;
|
||||
assign ws_ribp.wstrb = host_active ? host_wstrb : dma_rib.wstrb;
|
||||
assign ws_ribp.valid = host_active ? host_valid : dma_ws_valid;
|
||||
assign ws_ribp.addr = host_active ? host_addr : bus_addr_q;
|
||||
assign ws_ribp.wdata = host_active ? host_wdata : dma_rib.wdata;
|
||||
assign ws_ribp.wstrb = host_active ? host_wstrb : dma_rib.wstrb;
|
||||
|
||||
assign dma_rib.cmd_ready = bus_state_q == BUS_IDLE;
|
||||
assign dma_rib.w_ready = (bus_state_q == BUS_WRITE_DATA) && ws_ribp.ready;
|
||||
assign dma_rib.rsp_valid = (bus_state_q == BUS_READ_RESP) || (bus_state_q == BUS_WRITE_RESP);
|
||||
assign dma_rib.rdata = pixels[bus_addr_q[4:2]];
|
||||
assign dma_rib.resp_err = 1'b0;
|
||||
assign dma_rib.resp_code = `RIB_RESP_OK;
|
||||
assign dma_rib.rsp_beat = 2'd0;
|
||||
assign dma_rib.rsp_last = 1'b1;
|
||||
assign dma_ws_valid = (bus_state_q == BUS_WRITE_DATA) && dma_rib.w_valid;
|
||||
assign dma_rib.cmd_ready = bus_state_q == BUS_IDLE;
|
||||
assign dma_rib.w_ready = (bus_state_q == BUS_WRITE_DATA) && ws_ribp.ready;
|
||||
assign dma_rib.rsp_valid = (bus_state_q == BUS_READ_RESP) || (bus_state_q == BUS_WRITE_RESP);
|
||||
assign dma_rib.rdata = pixels[bus_addr_q[4:2]];
|
||||
assign dma_rib.resp_err = 1'b0;
|
||||
assign dma_rib.resp_code = `RIB_RESP_OK;
|
||||
assign dma_rib.rsp_beat = 2'd0;
|
||||
assign dma_rib.rsp_last = 1'b1;
|
||||
assign dma_ws_valid = (bus_state_q == BUS_WRITE_DATA) && dma_rib.w_valid;
|
||||
assign i2s_tx_axis.tready = 1'b0;
|
||||
assign i2s_rx_axis.tdata = '0;
|
||||
assign i2s_rx_axis.tkeep = '0;
|
||||
assign i2s_rx_axis.tstrb = '0;
|
||||
assign i2s_rx_axis.tlast = 1'b0;
|
||||
assign i2s_rx_axis.tid = '0;
|
||||
assign i2s_rx_axis.tdest = '0;
|
||||
assign i2s_rx_axis.tuser = '0;
|
||||
assign i2s_rx_axis.tvalid = 1'b0;
|
||||
assign dvp_rx_axis.tdata = '0;
|
||||
assign dvp_rx_axis.tkeep = '0;
|
||||
assign dvp_rx_axis.tstrb = '0;
|
||||
assign dvp_rx_axis.tlast = 1'b0;
|
||||
assign dvp_rx_axis.tid = '0;
|
||||
assign dvp_rx_axis.tdest = '0;
|
||||
assign dvp_rx_axis.tuser = '0;
|
||||
assign dvp_rx_axis.tvalid = 1'b0;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
@@ -142,7 +171,10 @@ module ws2812_dma_tb;
|
||||
.error_addr_o(dma_error_addr),
|
||||
.fsm_o (dma_fsm),
|
||||
.hw_trg (hw_trg),
|
||||
.rib (dma_rib)
|
||||
.rib (dma_rib),
|
||||
.i2s_tx_axis (i2s_tx_axis),
|
||||
.i2s_rx_axis (i2s_rx_axis),
|
||||
.dvp_rx_axis (dvp_rx_axis)
|
||||
);
|
||||
|
||||
ribp_ws2812 #(
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
"""Directed tests for the active AXI4 fabric adapters."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_axi42ribp_supports_bursts_backpressure_and_errors(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
output = tmp_path / "axi42ribp_burst_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"axi42ribp_burst_tb",
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi42ribp_burst.sv"),
|
||||
str(ROOT / "tests/rtl/axi42ribp_burst_tb.sv"),
|
||||
"-Mdir",
|
||||
str(tmp_path / "obj"),
|
||||
"-o",
|
||||
str(output),
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env={
|
||||
**os.environ,
|
||||
"CCACHE_DIR": str(ccache_tmp),
|
||||
"CCACHE_TEMPDIR": str(ccache_tmp),
|
||||
},
|
||||
)
|
||||
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||
assert "AXI4 to RIBP burst bridge test passed" in result.stdout
|
||||
|
||||
|
||||
def test_axi4_interconnect_classifies_decode_protocol_and_access_errors(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
memory_map = tmp_path / "memory_map"
|
||||
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(memory_map),
|
||||
"--have-sram-if",
|
||||
"NO",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
output = tmp_path / "axi4_interconnect_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"axi4_interconnect_tb",
|
||||
"-I" + str(memory_map / "rtl"),
|
||||
"-I" + str(ROOT / "rtl/mini/top"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/stream/round_robin_arbiter.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_interconnect.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_error_slave.sv"),
|
||||
str(ROOT / "tests/rtl/axi4_interconnect_tb.sv"),
|
||||
"-Mdir",
|
||||
str(tmp_path / "obj"),
|
||||
"-o",
|
||||
str(output),
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env={
|
||||
**os.environ,
|
||||
"CCACHE_DIR": str(ccache_tmp),
|
||||
"CCACHE_TEMPDIR": str(ccache_tmp),
|
||||
},
|
||||
)
|
||||
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||
assert "AXI4 interconnect fault classification test passed" in result.stdout
|
||||
+2
-1
@@ -40,6 +40,7 @@ def test_dma_reports_bus_errors_and_transfers_exact_word_count(tmp_path: Path) -
|
||||
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
||||
f"+incdir+{ROOT / 'rtl/mini/top'}",
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_stream_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/rib_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv"),
|
||||
@@ -69,4 +70,4 @@ def test_dma_reports_bus_errors_and_transfers_exact_word_count(tmp_path: Path) -
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
assert "dma error and burst performance test passed" in result.stdout
|
||||
assert "dma error, burst performance, and AXI4-Stream test passed" in result.stdout
|
||||
@@ -148,6 +148,7 @@ def test_bus_fault_responder_handles_reserved_and_unmapped_addresses(tmp_path: P
|
||||
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/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ram_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/rib_if.sv"),
|
||||
|
||||
@@ -39,6 +39,7 @@ def test_bus_preserves_incr4_and_rejects_illegal_bursts(tmp_path: Path) -> None:
|
||||
f"+incdir+{memory_map / 'rtl'}",
|
||||
f"+incdir+{ROOT / 'rtl/mini/top'}",
|
||||
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ram_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/rib_if.sv"),
|
||||
|
||||
@@ -737,7 +737,7 @@ def test_management_core_is_fixed_to_hazard3_with_debug() -> None:
|
||||
assert "CORE_$(CORE)" not in makefile
|
||||
assert "`ifdef CORE_" not in wrapper
|
||||
assert "`ifdef HAVE_DEBUG" not in wrapper
|
||||
assert "ahbl2ribp u_ahbl2ribp" in wrapper
|
||||
assert "ahbl2axi4 u_ahbl2axi4" in wrapper
|
||||
assert ".RESET_VECTOR (`SOC_CPU_RESET_ADDR)" in wrapper
|
||||
assert ".DEBUG_SUPPORT (1)" in wrapper
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "assign s_slv_sel_d[17] = u_i2c1_ribp_if.valid;" in routes
|
||||
assert "assign s_slv_resp_err[17] = u_i2c1_ribp_if.resp_err;" in routes
|
||||
assert "assign ribp.resp_err = |(s_slv_sel_q & s_slv_ready & s_slv_resp_err);" in routes
|
||||
assert "assign s_xpi_region_sel[1] = (ribp.addr <= `SOC_ADDR_FLASH_END);" in routes
|
||||
assert "SOC_ADDR_FLASH" not in routes
|
||||
assert "assign u_sdio_ribp_if.valid = 1'b0;" in routes
|
||||
assert gpio.count("// GPIO") == 64
|
||||
assert "u_uart1_if" not in gpio
|
||||
@@ -106,12 +106,12 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "assign user_ip.paddr = s_addr_q;" in apb_routes
|
||||
assert "({32{s_psel_q[7]}} & user_ip.prdata)" in apb_response
|
||||
assert "localparam int NSLV = 8;" in apb_declarations
|
||||
assert fabric.count("ribp_if u_") == 1
|
||||
assert fabric.count("rib_if u_") == 4
|
||||
assert ".mgmt_ribp(u_mgmt_ribp_if)" in bus_fabric
|
||||
assert ".user_rib(u_user_rib_if)" in bus_fabric
|
||||
assert ".apb_rib(u_apb_rib_if)" in bus_fabric
|
||||
assert ".rib(u_rib_if)" in bus_fabric
|
||||
assert fabric.count("axi4_if #(") == 5
|
||||
assert ".mgmt_axi4(u_mgmt_axi4_if)" in bus_fabric
|
||||
assert ".user_axi4(u_user_axi4_if)" in bus_fabric
|
||||
assert ".dma_axi4(u_dma_axi4_if)" in bus_fabric
|
||||
assert ".cfg_axi4(u_cfg_axi4_if)" in bus_fabric
|
||||
assert ".apb_axi4(u_apb_axi4_if)" in bus_fabric
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 32'h000E7BFC" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 13" in irq_config
|
||||
|
||||
@@ -96,6 +96,7 @@ def test_ws2812_accepts_dma_fixed_destination_backpressure(tmp_path: Path) -> No
|
||||
f"+incdir+{ROOT / 'rtl/mini/top'}",
|
||||
f"+incdir+{serial}",
|
||||
str(common / "interface/ribp_if.sv"),
|
||||
str(common / "interface/axi4_stream_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/rib_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(common / "utils/fifo.sv"),
|
||||
|
||||
Reference in new issue
Block a user