feat: add HP mailbox and PLIC tests; enhance existing test coverage

- Updated axi4_interconnect_tb to include an additional master and issue high-priority access tests.
- Introduced hp_mailbox_tb for testing the HP mailbox functionality, including register and doorbell operations.
- Added plic_tb to validate PLIC priority, claim, and completion mechanisms.
- Enhanced pll_ctrl_tb to initialize additional system control signals.
- Updated soc_irq_topology_tb to account for new IRQ sources and validate IRQ signal behavior.
- Improved sysctrl_tb to include tests for HP lifecycle control and status registers.
- Added tests for HP boot bundle layout, CRC, and payload validation.
- Introduced test_hp_mailbox.py for RTL regression testing of the HP mailbox.
- Added test_hp_platform.py to validate HP platform configuration and generated-source boundaries.
- Enhanced test_librelane_flow.py to ensure correct signal placement in chip configuration.
- Added performance log tests to validate LP and HP coremark ratios.
- Updated test_soc_topology.py to reflect changes in IRQ and peripheral mappings.
This commit is contained in:
maksyuki committed 2026-08-27 19:26:32 +08:00
1 parent f953ef7137
commit 8ba8a0ad47
101 files changed
+4880 -111

No files matched your search

+273
View File
@@ -0,0 +1,273 @@
`timescale 1ns / 1ps
`include "axi4_define.svh"
module axi4_downsizer_64to32_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) wide (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) narrow (
.aclk (clk_i),
.aresetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
axi4_downsizer_64to32 u_dut (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.wide (wide),
.narrow (narrow)
);
task automatic init_bus;
begin
wide.awid = '0;
wide.awaddr = '0;
wide.awlen = '0;
wide.awsize = `AXI4_BURST_SIZE_8BYTES;
wide.awburst = `AXI4_BURST_TYPE_INCR;
wide.awlock = `AXI4_LOCK_NORM;
wide.awcache = `AXI4_CACHE_NO_BUF;
wide.awprot = `AXI4_PROT_DATA;
wide.awqos = `AXI4_QOS_NORMAL;
wide.awregion = `AXI4_REGION_NORMAL;
wide.awuser = '0;
wide.awvalid = 1'b0;
wide.wdata = '0;
wide.wstrb = '0;
wide.wlast = 1'b0;
wide.wuser = '0;
wide.wvalid = 1'b0;
wide.bready = 1'b0;
wide.arid = '0;
wide.araddr = '0;
wide.arlen = '0;
wide.arsize = `AXI4_BURST_SIZE_8BYTES;
wide.arburst = `AXI4_BURST_TYPE_INCR;
wide.arlock = `AXI4_LOCK_NORM;
wide.arcache = `AXI4_CACHE_NO_BUF;
wide.arprot = `AXI4_PROT_DATA;
wide.arqos = `AXI4_QOS_NORMAL;
wide.arregion = `AXI4_REGION_NORMAL;
wide.aruser = '0;
wide.arvalid = 1'b0;
wide.rready = 1'b0;
narrow.awready = 1'b0;
narrow.wready = 1'b0;
narrow.bid = '0;
narrow.bresp = `AXI4_RESP_OKAY;
narrow.buser = '0;
narrow.bvalid = 1'b0;
narrow.arready = 1'b0;
narrow.rid = '0;
narrow.rdata = '0;
narrow.rresp = `AXI4_RESP_OKAY;
narrow.rlast = 1'b0;
narrow.ruser = '0;
narrow.rvalid = 1'b0;
end
endtask
task automatic accept_read(input logic [31:0] address, input logic [7:0] length,
input logic [2:0] size, input logic [2:0] id,
input logic [7:0] expected_length);
begin
@(negedge clk_i);
wide.araddr = address;
wide.arlen = length;
wide.arsize = size;
wide.arid = id;
wide.arvalid = 1'b1;
#1;
if (wide.arready) $fatal(1, "read address ignored narrow backpressure");
narrow.arready = 1'b1;
#1;
if (!narrow.arvalid || narrow.araddr != address || narrow.arlen != expected_length ||
narrow.arsize != ((size == 3'd3) ? 3'd2 : size)) begin
$fatal(1, "read address conversion mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
wide.arvalid = 1'b0;
narrow.arready = 1'b0;
end
endtask
task automatic accept_write(input logic [31:0] address, input logic [7:0] length,
input logic [2:0] size, input logic [2:0] id,
input logic [7:0] expected_length);
begin
@(negedge clk_i);
wide.awaddr = address;
wide.awlen = length;
wide.awsize = size;
wide.awid = id;
wide.awvalid = 1'b1;
#1;
if (wide.awready) $fatal(1, "write address ignored narrow backpressure");
narrow.awready = 1'b1;
#1;
if (!narrow.awvalid || narrow.awaddr != address || narrow.awlen != expected_length ||
narrow.awsize != ((size == 3'd3) ? 3'd2 : size)) begin
$fatal(1, "write address conversion mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
wide.awvalid = 1'b0;
narrow.awready = 1'b0;
end
endtask
task automatic return_write_response(input logic [2:0] expected_id, input logic [1:0] response);
begin
@(negedge clk_i);
narrow.bresp = response;
narrow.bvalid = 1'b1;
wide.bready = 1'b0;
#1;
if (!narrow.bready) $fatal(1, "narrow write response was not accepted into buffer");
@(posedge clk_i);
@(negedge clk_i);
narrow.bvalid = 1'b0;
#1;
if (!wide.bvalid || wide.bid != expected_id || wide.bresp != response) begin
$fatal(1, "buffered write response mismatch");
end
repeat (2) @(posedge clk_i);
if (!wide.bvalid || wide.bid != expected_id || wide.bresp != response) begin
$fatal(1, "write response changed under backpressure");
end
@(negedge clk_i);
wide.bready = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
wide.bready = 1'b0;
end
endtask
initial begin
init_bus();
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
accept_read(32'h0000_0040, 8'd0, 3'd3, 3'd5, 8'd1);
@(negedge clk_i);
narrow.rdata = 32'h1122_3344;
narrow.rresp = `AXI4_RESP_SLAVE_ERROR;
narrow.rlast = 1'b0;
narrow.rvalid = 1'b1;
wide.rready = 1'b0;
#1;
if (!narrow.rready || wide.rvalid) $fatal(1, "lower read beat was not buffered");
@(posedge clk_i);
@(negedge clk_i);
narrow.rdata = 32'h5566_7788;
narrow.rresp = `AXI4_RESP_OKAY;
narrow.rlast = 1'b1;
#1;
if (!wide.rvalid || narrow.rready || wide.rid != 3'd5 ||
wide.rdata != 64'h5566_7788_1122_3344 || wide.rresp != `AXI4_RESP_SLAVE_ERROR ||
!wide.rlast) begin
$fatal(1, "64-bit read assembly or backpressure mismatch");
end
repeat (2) @(posedge clk_i);
@(negedge clk_i);
wide.rready = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
wide.rready = 1'b0;
narrow.rvalid = 1'b0;
accept_read(32'h0000_0000, 8'd1, 3'd2, 3'd3, 8'd1);
@(negedge clk_i);
narrow.rdata = 32'hA5A5_0000;
narrow.rresp = `AXI4_RESP_OKAY;
narrow.rlast = 1'b0;
narrow.rvalid = 1'b1;
wide.rready = 1'b1;
#1;
if (wide.rdata != 64'h0000_0000_A5A5_0000 || wide.rid != 3'd3) begin
$fatal(1, "lower 32-bit read lane mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
narrow.rdata = 32'hA5A5_0001;
narrow.rlast = 1'b1;
#1;
if (wide.rdata != 64'hA5A5_0001_0000_0000 || !wide.rlast) begin
$fatal(1, "upper 32-bit read lane mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
wide.rready = 1'b0;
narrow.rvalid = 1'b0;
accept_write(32'h0000_0080, 8'd0, 3'd3, 3'd6, 8'd1);
@(negedge clk_i);
wide.wdata = 64'h1122_3344_5566_7788;
wide.wstrb = 8'hF3;
wide.wlast = 1'b1;
wide.wvalid = 1'b1;
narrow.wready = 1'b1;
#1;
if (narrow.wdata != 32'h5566_7788 || narrow.wstrb != 4'h3 || narrow.wlast || wide.wready) begin
$fatal(1, "lower 64-bit write split mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
#1;
if (narrow.wdata != 32'h1122_3344 || narrow.wstrb != 4'hF || !narrow.wlast ||
!wide.wready) begin
$fatal(1, "upper 64-bit write split mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
wide.wvalid = 1'b0;
narrow.wready = 1'b0;
return_write_response(3'd6, `AXI4_RESP_DECODE_ERROR);
accept_write(32'h0000_0004, 8'd1, 3'd2, 3'd2, 8'd1);
@(negedge clk_i);
wide.wdata = 64'hCAFE_0000_DEAD_0000;
wide.wstrb = 8'hF0;
wide.wlast = 1'b0;
wide.wvalid = 1'b1;
narrow.wready = 1'b1;
#1;
if (narrow.wdata != 32'hCAFE_0000 || narrow.wstrb != 4'hF || !wide.wready) begin
$fatal(1, "upper 32-bit write lane mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
wide.wdata = 64'hDEAD_0000_CAFE_0001;
wide.wstrb = 8'h0F;
wide.wlast = 1'b1;
#1;
if (narrow.wdata != 32'hCAFE_0001 || narrow.wstrb != 4'hF || !wide.wready) begin
$fatal(1, "lower 32-bit write lane mismatch");
end
@(posedge clk_i);
@(negedge clk_i);
wide.wvalid = 1'b0;
narrow.wready = 1'b0;
return_write_response(3'd2, `AXI4_RESP_OKAY);
$display("AXI4 64-to-32 downsizer test passed");
$finish;
end
endmodule
+48 -1
View File
@@ -4,7 +4,7 @@
`include "rib_defs.svh"
module axi4_interconnect_tb;
localparam int NumMasters = 7;
localparam int NumMasters = 8;
localparam int NumTargets = 9;
logic clk_i = 1'b0;
@@ -288,6 +288,50 @@ module axi4_interconnect_tb;
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)
@@ -295,6 +339,8 @@ module axi4_interconnect_tb;
`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;
@@ -303,6 +349,7 @@ module axi4_interconnect_tb;
issue_mgmt_error_read(32'h3000_0000, 8'd16, `AXI4_RESP_SLAVE_ERROR, `RIB_RESP_BURSTERR);
issue_denied_user_write(32'h1000_B000);
issue_contending_sdio_faults();
issue_hp_accesses();
$display("AXI4 interconnect fault classification test passed");
$finish;
+89
View File
@@ -0,0 +1,89 @@
`timescale 1ns / 1ps
module hp_mailbox_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic lp_irq_o;
logic hp_irq_o;
logic [31:0] value;
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
apb4_hp_mailbox u_dut (
.clk_i,
.rst_n_i,
.apb4,
.lp_irq_o,
.hp_irq_o
);
task automatic apb_write(input logic [31:0] address, input logic [31:0] data);
begin
@(negedge clk_i);
apb4.paddr = address;
apb4.pwdata = data;
apb4.pstrb = 4'hf;
apb4.pwrite = 1'b1;
apb4.psel = 1'b1;
apb4.penable = 1'b1;
while (!apb4.pready) @(negedge clk_i);
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.pstrb = '0;
end
endtask
task automatic apb_read(input logic [31:0] address, output logic [31:0] data);
begin
@(negedge clk_i);
apb4.paddr = address;
apb4.pstrb = '0;
apb4.pwrite = 1'b0;
apb4.psel = 1'b1;
apb4.penable = 1'b1;
while (!apb4.pready) @(negedge clk_i);
data = apb4.prdata;
apb4.psel = 1'b0;
apb4.penable = 1'b0;
end
endtask
initial begin
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.paddr = '0;
apb4.pwdata = '0;
apb4.pstrb = '0;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
apb_read(32'h0, value);
if (value != 32'h0001_0000) $fatal(1, "mailbox version mismatch");
apb_write(32'h44, 32'h1);
apb_write(32'h10, 32'h1);
apb_write(32'h18, 32'h1234);
apb_write(32'h1c, 32'h1);
if (!hp_irq_o) $fatal(1, "LP-to-HP doorbell did not assert");
apb_read(32'h18, value);
if (value != 32'h1234) $fatal(1, "LP sequence did not persist");
apb_write(32'h40, 32'h1);
if (hp_irq_o) $fatal(1, "HP interrupt did not clear");
apb_write(32'h34, 32'h1);
apb_write(32'h20, 32'h1);
apb_write(32'h2c, 32'h1);
if (!lp_irq_o) $fatal(1, "HP-to-LP doorbell did not assert");
apb_write(32'h30, 32'h1);
if (lp_irq_o) $fatal(1, "LP interrupt did not clear");
$display("HP mailbox register and doorbell test passed");
$finish;
end
endmodule
+92
View File
@@ -0,0 +1,92 @@
`timescale 1ns / 1ps
module plic_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [31:0] source_i = '0;
logic [ 1:0] context_irq_o;
logic [31:0] value;
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
apb4_plic u_dut (
.clk_i,
.rst_n_i,
.source_i,
.apb4,
.context_irq_o
);
task automatic apb_write(input logic [31:0] address, input logic [31:0] data);
begin
@(negedge clk_i);
apb4.paddr = address;
apb4.pwdata = data;
apb4.pstrb = 4'hf;
apb4.pwrite = 1'b1;
apb4.psel = 1'b1;
apb4.penable = 1'b1;
while (!apb4.pready) @(negedge clk_i);
if (apb4.pslverr) $fatal(1, "PLIC write failed at %h", address);
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.pstrb = '0;
end
endtask
task automatic apb_read(input logic [31:0] address, output logic [31:0] data);
begin
@(negedge clk_i);
apb4.paddr = address;
apb4.pstrb = '0;
apb4.pwrite = 1'b0;
apb4.psel = 1'b1;
apb4.penable = 1'b1;
while (!apb4.pready) @(negedge clk_i);
if (apb4.pslverr) $fatal(1, "PLIC read failed at %h", address);
data = apb4.prdata;
apb4.psel = 1'b0;
apb4.penable = 1'b0;
end
endtask
initial begin
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.paddr = '0;
apb4.pwdata = '0;
apb4.pstrb = '0;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
apb_write(32'h0000_0004, 32'd3);
apb_write(32'h0000_0008, 32'd5);
apb_write(32'h0000_2080, 32'h0000_0006);
apb_write(32'h0020_1000, 32'd0);
source_i[1] = 1'b1;
source_i[2] = 1'b1;
repeat (2) @(posedge clk_i);
if (!context_irq_o[1]) $fatal(1, "supervisor context IRQ did not assert");
apb_read(32'h0020_1004, value);
if (value != 32'd2) $fatal(1, "highest-priority source was not claimed");
source_i[2] = 1'b0;
apb_write(32'h0020_1004, 32'd2);
repeat (2) @(posedge clk_i);
apb_read(32'h0020_1004, value);
if (value != 32'd1) $fatal(1, "remaining source was not claimed");
source_i[1] = 1'b0;
apb_write(32'h0020_1004, 32'd1);
repeat (2) @(posedge clk_i);
if (context_irq_o[1]) $fatal(1, "supervisor context IRQ did not clear");
$display("PLIC priority, claim, and completion test passed");
$finish;
end
endmodule
+21 -8
View File
@@ -120,14 +120,27 @@ module pll_ctrl_tb;
endtask
initial begin
apb4.psel = 1'b0;
apb4.paddr = '0;
apb4.pwdata = '0;
apb4.pstrb = '0;
sysctrl.user_bus_idle_i = 1'b1;
sysctrl.fault_access_i = 1'b0;
sysctrl.fault_master_i = '0;
sysctrl.rtc_wake_i = 1'b0;
apb4.psel = 1'b0;
apb4.paddr = '0;
apb4.pwdata = '0;
apb4.pstrb = '0;
sysctrl.user_bus_idle_i = 1'b1;
sysctrl.fault_access_i = 1'b0;
sysctrl.fault_master_i = '0;
sysctrl.fault_code_i = '0;
sysctrl.perf_mgmt_wait_i = '0;
sysctrl.perf_user_wait_i = '0;
sysctrl.perf_dma_wait_i = '0;
sysctrl.perf_sdio0_wait_i = '0;
sysctrl.perf_sdio1_wait_i = '0;
sysctrl.perf_usb2_wait_i = '0;
sysctrl.perf_apb4_periph_wait_i = '0;
sysctrl.perf_apb4_system_wait_i = '0;
sysctrl.perf_sdram_wait_i = '0;
sysctrl.perf_psram_wait_i = '0;
sysctrl.perf_flash_wait_i = '0;
sysctrl.rtc_wake_i = 1'b0;
sysctrl.hp_present_i = 1'b0;
#100;
rst_n_i = 1'b1;
repeat (2) begin
+3 -1
View File
@@ -40,6 +40,8 @@ module soc_irq_topology_tb;
17: expect_irq(32'd1 << 21);
18: expect_irq(32'd1 << 23);
19: expect_irq(32'd1 << 24);
20: expect_irq(32'd1 << 25);
21: expect_irq(32'd1 << 26);
default: expect_irq(32'd1 << (bit_index + 7));
endcase
end
@@ -64,7 +66,7 @@ module soc_irq_topology_tb;
$fatal(1, "SDIO core IRQ bits are not low when sources are low: IRQ10=%b IRQ21=%b",
s_irq[10], s_irq[21]);
end
if ((s_irq[31:25] !== '0) || (s_irq[19:18] !== '0)) begin
if ((s_irq[31:27] !== '0) || (s_irq[19:18] !== '0)) begin
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq);
end
+28 -1
View File
@@ -93,6 +93,7 @@ module sysctrl_tb;
sysctrl.perf_psram_wait_i = 64'd17;
sysctrl.perf_flash_wait_i = 64'd18;
sysctrl.rtc_wake_i = 1'b0;
sysctrl.hp_present_i = 1'b0;
pll_ctrl.req_ready_i = 1'b1;
pll_ctrl.rsp_active_sel_i = '0;
pll_ctrl.rsp_active_valid_i = 1'b0;
@@ -216,7 +217,33 @@ module sysctrl_tb;
$fatal(1, "RTC wake sticky status W1C failed");
end
$display("SystemCtrl register, lifecycle, fault, performance, and RTC wake test passed");
read_register(32'h1000_B0A8, read_data);
if (read_data !== 32'h0000_0000) $fatal(1, "absent HP status was not zero");
write_register(32'h1000_B0A4, 32'h0000_0001);
write_register(32'h1000_B0AC, 32'h0000_0001);
if (sysctrl.hp_release_o || sysctrl.debug_hp_select_o) begin
$fatal(1, "absent HP accepted lifecycle control");
end
sysctrl.hp_present_i = 1'b1;
read_register(32'h1000_B0A8, read_data);
if (read_data !== 32'h0000_0005) $fatal(1, "present HP reset status mismatch");
write_register(32'h1000_B0AC, 32'h0000_0001);
if (!sysctrl.debug_hp_select_o) $fatal(1, "HP debug selection was not accepted in reset");
write_register(32'h1000_B0A4, 32'h0000_0001);
read_register(32'h1000_B0A8, read_data);
if ((read_data !== 32'h0000_0003) || !sysctrl.hp_release_o) begin
$fatal(1, "HP release status mismatch");
end
write_register(32'h1000_B0AC, 32'h0000_0000);
if (!sysctrl.debug_hp_select_o) $fatal(1, "running HP allowed JTAG selection change");
write_register(32'h1000_B0A4, 32'h0000_0000);
write_register(32'h1000_B0AC, 32'h0000_0000);
if (sysctrl.hp_release_o || sysctrl.debug_hp_select_o) begin
$fatal(1, "HP reset/debug return did not complete");
end
$display("SystemCtrl register, lifecycle, fault, performance, RTC wake, and HP test passed");
$finish;
end
endmodule