feat: enhance AXI4 and RIBP interfaces with burst support and address generation

- Added burst handling to the AXI42RAM and AXI42RIBP modules, including support for fixed, increment, and wrap burst types.
- Introduced address generation logic for read and write operations based on burst parameters.
- Updated the AXI4 interconnect to validate burst types and lengths, ensuring compatibility with the AXI4 protocol.
- Modified the SDRAM controller and testbench to accommodate the new burst handling features.
- Enhanced test cases to verify the correct behavior of burst transactions and address patterns.
- Adjusted memory map and topology tests to reflect changes in the SDRAM size and interface connections.
This commit is contained in:
maksyuki committed 2026-08-13 22:37:01 +08:00
1 parent 2aacaf7507
commit 0077546d6b
27 files changed
+707 -360

No files matched your search

+44 -1
View File
@@ -235,6 +235,46 @@ module axi42ribp_burst_tb;
end
endtask
task automatic issue_address_pattern_read(input logic [31:0] address, input logic [7:0] length,
input logic [1:0] burst);
integer beat;
logic [31:0] expected_address;
logic [31:0] burst_bytes;
begin
burst_bytes = (length + 1) * 4;
@(negedge clk_i);
axi4.araddr = address;
axi4.arlen = length;
axi4.arburst = burst;
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 (burst == `AXI4_BURST_TYPE_FIXED) begin
expected_address = address;
end else begin
expected_address = (address & ~(burst_bytes - 1)) |
((address + (beat * 4)) & (burst_bytes - 1));
end
if (axi4.rdata != memory[expected_address[7:2]] ||
axi4.rresp != `AXI4_RESP_OKAY || axi4.rlast != (beat == length)) begin
$fatal(1, "address pattern mismatch beat=%0d addr=%08x data=%08x", beat,
expected_address, axi4.rdata);
end
beat = beat + 1;
end
end
@(negedge clk_i);
axi4.rready = 1'b0;
axi4.arburst = `AXI4_BURST_TYPE_INCR;
end
endtask
initial begin
init_axi4();
for (int index = 0; index < 64; index++) memory[index] = '0;
@@ -242,6 +282,9 @@ module axi42ribp_burst_tb;
rst_n_i = 1'b1;
issue_write4(32'h0000_0040);
issue_read4(32'h0000_0040);
for (int index = 0; index < 64; index++) memory[index] = 32'h5000_0000 + index;
issue_address_pattern_read(32'h0000_0020, 8'd3, `AXI4_BURST_TYPE_FIXED);
issue_address_pattern_read(32'h0000_002C, 8'd3, `AXI4_BURST_TYPE_WRAP);
issue_illegal_read(32'h0000_0080);
issue_early_last_write(32'h0000_00C0);
burst_cycles = cycle_count;
@@ -256,7 +299,7 @@ module axi42ribp_burst_tb;
$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");
if (target_accesses != 49) $fatal(1, "unexpected RIBP access count");
$display("AXI4 to RIBP burst bridge test passed");
$finish;
end
+4 -3
View File
@@ -6,6 +6,7 @@ module ribp_topology_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
ribp_if ribp ();
ribp_if sdram_cfg_ribp ();
`include "ribp_interfaces.svh"
`include "ribp_routes.svh"
@@ -92,7 +93,7 @@ module ribp_topology_tb;
u_dma_ribp_if.ready = 1'b1;
u_sysctrl_ribp_if.ready = 1'b1;
u_clint_ribp_if.ready = 1'b1;
u_sdram_ribp_if.ready = 1'b1;
sdram_cfg_ribp.ready = 1'b1;
u_dvp_ribp_if.ready = 1'b1;
u_sdio_ribp_if.ready = 1'b1;
u_opipsram_ribp_if.ready = 1'b1;
@@ -111,7 +112,7 @@ module ribp_topology_tb;
u_dma_ribp_if.rdata = 32'hAAAA_AAAA;
u_sysctrl_ribp_if.rdata = 32'hBBBB_BBBB;
u_clint_ribp_if.rdata = 32'hCCCC_CCCC;
u_sdram_ribp_if.rdata = 32'hDDDD_DDDD;
sdram_cfg_ribp.rdata = 32'hDDDD_DDDD;
u_dvp_ribp_if.rdata = 32'hEEEE_EEEE;
u_sdio_ribp_if.rdata = 32'hF0F0_F0F0;
u_opipsram_ribp_if.rdata = 32'h0F0F_0F0F;
@@ -130,7 +131,7 @@ module ribp_topology_tb;
u_dma_ribp_if.resp_err = 1'b0;
u_sysctrl_ribp_if.resp_err = 1'b0;
u_clint_ribp_if.resp_err = 1'b0;
u_sdram_ribp_if.resp_err = 1'b0;
sdram_cfg_ribp.resp_err = 1'b0;
u_dvp_ribp_if.resp_err = 1'b0;
u_sdio_ribp_if.resp_err = 1'b0;
u_opipsram_ribp_if.resp_err = 1'b0;
+96 -28
View File
@@ -5,7 +5,16 @@ module sdram_data_tb;
logic rst_n_i = 1'b0;
wire [15:0] s_dq;
logic [31:0] s_read_data;
ribp_if rib ();
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
.aclk (clk_i),
.aresetn(rst_n_i)
);
ribp_if cfg_ribp ();
sdram_if sdram ();
always #5 clk_i = ~clk_i;
@@ -13,11 +22,12 @@ module sdram_data_tb;
assign s_dq = sdram.oe_o ? sdram.dq_o : 'z;
assign sdram.dq_i = s_dq;
ribp_sdram u_ribp_sdram (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (rib),
.sdram (sdram)
axi4_sdram u_axi4_sdram (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.axi4 (axi4),
.cfg_ribp(cfg_ribp),
.sdram (sdram)
);
`ifdef SDRAM_TIMING_MODEL
@@ -48,44 +58,96 @@ module sdram_data_tb;
);
`endif
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;
cfg_ribp.valid = 1'b0;
cfg_ribp.addr = '0;
cfg_ribp.wdata = '0;
cfg_ribp.wstrb = '0;
end
endtask
task automatic write_word(input logic [31:0] address, input logic [31:0] data,
input logic [3:0] strobe);
begin
@(negedge clk_i);
rib.addr = address;
rib.wdata = data;
rib.wstrb = strobe;
rib.valid = 1'b1;
do begin
@(posedge clk_i);
end while (!rib.ready);
axi4.awaddr = address;
axi4.awlen = 8'd0;
axi4.awvalid = 1'b1;
do @(posedge clk_i); while (!axi4.awready);
@(negedge clk_i);
rib.valid = 1'b0;
rib.wstrb = '0;
axi4.awvalid = 1'b0;
axi4.wdata = data;
axi4.wstrb = strobe;
axi4.wlast = 1'b1;
axi4.wvalid = 1'b1;
do @(posedge clk_i); while (!axi4.wready);
@(negedge clk_i);
axi4.wvalid = 1'b0;
axi4.wlast = 1'b0;
axi4.bready = 1'b1;
do @(posedge clk_i); while (!axi4.bvalid);
if (axi4.bresp != `AXI4_RESP_OKAY) begin
$fatal(1, "AXI4 SDRAM write failed at %08x", address);
end
@(negedge clk_i);
axi4.bready = 1'b0;
end
endtask
task automatic read_word(input logic [31:0] address);
begin
@(negedge clk_i);
rib.addr = address;
rib.wdata = '0;
rib.wstrb = '0;
rib.valid = 1'b1;
do begin
@(posedge clk_i);
end while (!rib.ready);
s_read_data = rib.rdata;
axi4.araddr = address;
axi4.arlen = 8'd0;
axi4.arvalid = 1'b1;
do @(posedge clk_i); while (!axi4.arready);
@(negedge clk_i);
rib.valid = 1'b0;
axi4.arvalid = 1'b0;
axi4.rready = 1'b1;
do @(posedge clk_i); while (!axi4.rvalid);
s_read_data = axi4.rdata;
if (axi4.rresp != `AXI4_RESP_OKAY || !axi4.rlast) begin
$fatal(1, "AXI4 SDRAM read failed at %08x", address);
end
@(negedge clk_i);
axi4.rready = 1'b0;
end
endtask
initial begin
rib.addr = '0;
rib.valid = 1'b0;
rib.wdata = '0;
rib.wstrb = '0;
init_axi4();
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
@@ -104,6 +166,12 @@ module sdram_data_tb;
$fatal(1, "masked SDRAM readback was %08x", s_read_data);
end
write_word(`SOC_ADDR_SDRAM_BASE + 32'h03FF_FFFC, 32'hCAFE_BABE, 4'b1111);
read_word(`SOC_ADDR_SDRAM_BASE + 32'h03FF_FFFC);
if (s_read_data !== 32'hCAFE_BABE) begin
$fatal(1, "high-address SDRAM readback was %08x", s_read_data);
end
$display("sdram data integrity test passed");
$finish;
end
+1
View File
@@ -33,6 +33,7 @@ def test_axi42ribp_supports_bursts_backpressure_and_errors(tmp_path: Path) -> No
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/managed/clusterip/common/rtl/interface/axi4_addr_gen.sv"),
str(ROOT / "rtl/mini/top/axi42ribp_burst.sv"),
str(ROOT / "tests/rtl/axi42ribp_burst_tb.sv"),
"-Mdir",
+1 -1
View File
@@ -56,7 +56,7 @@ def test_generated_artifacts_share_the_capacity_baseline(tmp_path: Path) -> None
assert "`define CPU_RESET_ADDR `SOC_CPU_RESET_ADDR" in rtl
assert "`define SOC_ADDR_IS_RESERVED(addr)" in rtl
assert "RS_SOC_PSRAM_SIZE UINT32_C(0x00800000)" in header
assert "RS_SOC_SDRAM_SIZE UINT32_C(0x02000000)" in header
assert "RS_SOC_SDRAM_SIZE UINT32_C(0x04000000)" in header
assert "RS_SOC_SPISD_SIZE UINT32_C(0x40000000)" in header
assert "#ifdef __ASSEMBLER__" in header
assert "#define UINT32_C(value) value" in header
+12 -2
View File
@@ -35,9 +35,14 @@ def test_sdram_controller_preserves_full_and_masked_writes(tmp_path: Path) -> No
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{generated / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{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/interface/axi4_addr_gen.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/mini/top/axi42ribp_burst.sv"),
str(ROOT / "rtl/mini/top/ribp_arbiter2.sv"),
str(ROOT / "rtl/ip/memory/sdram.sv"),
str(ROOT / "rtl/ip/memory/sdram_clkgen.sv"),
str(ROOT / "rtl/ip/memory/sdram_reg.sv"),
@@ -95,10 +100,15 @@ def test_sdram_controller_preserves_data_with_micron_timing_model(tmp_path: Path
"+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/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl/interface'}",
f"+incdir+{ROOT / 'rtl/managed/third_party/model/sdram'}",
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/axi4_addr_gen.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/mini/top/axi42ribp_burst.sv"),
str(ROOT / "rtl/mini/top/ribp_arbiter2.sv"),
str(ROOT / "rtl/ip/memory/sdram.sv"),
str(ROOT / "rtl/ip/memory/sdram_clkgen.sv"),
str(ROOT / "rtl/ip/memory/sdram_reg.sv"),
+2 -1
View File
@@ -73,7 +73,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
irq_sva = (tmp_path / "rtl/soc_irq_sva.svh").read_text(encoding="utf-8")
filelist = (tmp_path / "soc_topology.fl").read_text(encoding="utf-8")
assert interfaces.count("ribp_if u_") == 18
assert interfaces.count("ribp_if u_") == 17
assert "nmi_if" not in interfaces
assert "soc_nmi" not in interfaces
assert "assign s_slv_sel_d[17] = u_i2c1_ribp_if.valid;" in routes
@@ -359,6 +359,7 @@ def test_generated_rib_routes_select_and_return_the_expected_target(tmp_path: Pa
f"+incdir+{memory_map_output / 'rtl'}",
f"+incdir+{topology_output / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl/interface'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "tests/rtl/ribp_topology_tb.sv"),
+1 -1
View File
@@ -52,7 +52,7 @@ def test_core_sdc_covers_current_clock_domains(tmp_path: Path) -> None:
assert "get_pins -quiet" in sdc
assert "get_ports -quiet" in sdc
assert "set clk_jtag_port [require_ports \"clock jtag\" {jtag_tck_i_pad}]" in sdc
assert "u_retrosoc.u_ip_ribp_wrapper.u_rib_dvp.u_dvp_pclk_clk_buf/clk_o" in sdc
assert "u_retrosoc.u_ip_ribp_wrapper.u_axi4_dvp.u_dvp_pclk_clk_buf/clk_o" in sdc
assert "-group [get_clocks {clk_external clk_system}]" in sdc
assert "set_clock_transition 0.1 [get_clocks {clk_dvp}]" in sdc
assert "set_input_transition" not in sdc