Files
retroSoC/tests/rtl/apu_irq_topology_tb.sv
T
maksyuki 52f619b9dc feat: add APU-P1 support and enhance test coverage
- 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.
2026-09-02 22:00:45 +08:00

272 lines
10 KiB
Systemverilog

`timescale 1ns / 1ps
`include "apu_define.svh"
`include "soc_irq_config.svh"
module apu_irq_topology_tb;
localparam logic [31:0] ApuBase = 32'h1001_3000;
localparam logic [11:0] Resource7Owner = 12'h1e0;
localparam logic [11:0] Resource7Control = 12'h1e4;
localparam logic [11:0] Resource7Fault = 12'h1ec;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic s_apu_idle;
logic s_apu_irq_raw;
logic [ 7:0] s_resource_idle;
logic [ 7:0] s_resource_block_ack;
logic [ 7:0] s_resource_irq_raw;
logic [ 7:0][1:0] s_resource_owner;
logic [ 7:0] s_resource_owner_lock;
logic [ 7:0] s_resource_quiesce;
logic [ 7:0] s_resource_reset;
logic [ 7:0] s_resource_irq_lp;
logic [ 7:0] s_resource_irq_hp;
logic [ 6:0] s_resource_irq_lp_compact;
logic [ 6:0] s_resource_irq_hp_compact;
logic s_resource_fault_irq;
logic s_cache_clean;
logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] s_apb4_periph_irq;
logic [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] s_apb4_system_irq;
logic [ `SOC_IRQ_VECTOR_WIDTH-1:0] s_irq;
logic [ 31:0] s_hp_plic_source;
logic [ 1:0] s_hp_plic_context_irq;
logic [ 31:0] s_value;
apb4_if u_apu_apb4_if (
.pclk (clk_i),
.presetn(rst_n_i)
);
apb4_if u_resource_apb4_if (
.pclk (clk_i),
.presetn(rst_n_i)
);
apb4_if u_plic_apb4_if (
.pclk (clk_i),
.presetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
assign s_resource_idle = {s_apu_idle, 7'h7f};
assign s_resource_block_ack = {
s_apu_idle && (s_resource_quiesce[7] || s_resource_reset[7]), 7'd0
};
assign s_resource_irq_raw = {s_apu_irq_raw, 7'd0};
assign s_resource_irq_lp_compact = {s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]};
assign s_resource_irq_hp_compact = {s_resource_irq_hp[7:6], s_resource_irq_hp[4:0]};
assign s_apb4_periph_irq = {s_resource_irq_lp_compact[6], 23'd0};
assign s_apb4_system_irq = '0;
assign s_hp_plic_source = {21'd0, s_resource_irq_hp_compact[6], 10'd0};
`include "soc_irq_wiring.svh"
apb4_apu u_apu (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.owner_i (s_resource_owner[7]),
.owner_lock_i (s_resource_owner_lock[7]),
.quiesce_i (s_resource_quiesce[7]),
.resource_reset_i(s_resource_reset[7]),
.apb4 (u_apu_apb4_if),
.idle_o (s_apu_idle),
.irq_o (s_apu_irq_raw)
);
resource_controller #(
.ResourceCount(8)
) u_resource_controller (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.idle_i (s_resource_idle),
.block_ack_i (s_resource_block_ack),
.irq_i (s_resource_irq_raw),
.cache_request_i(1'b0),
.cache_clean_o (s_cache_clean),
.owner_o (s_resource_owner),
.owner_lock_o (s_resource_owner_lock),
.quiesce_o (s_resource_quiesce),
.reset_o (s_resource_reset),
.irq_lp_o (s_resource_irq_lp),
.irq_hp_o (s_resource_irq_hp),
.fault_irq_o (s_resource_fault_irq),
.apb4 (u_resource_apb4_if)
);
apb4_plic u_hp_plic (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.source_i (s_hp_plic_source),
.apb4 (u_plic_apb4_if),
.context_irq_o(s_hp_plic_context_irq)
);
task automatic drive_apb_idle;
begin
u_apu_apb4_if.paddr = 32'd0;
u_apu_apb4_if.pprot = 3'd0;
u_apu_apb4_if.psel = 1'b0;
u_apu_apb4_if.penable = 1'b0;
u_apu_apb4_if.pwrite = 1'b0;
u_apu_apb4_if.pwdata = 32'd0;
u_apu_apb4_if.pstrb = 4'd0;
u_resource_apb4_if.paddr = 32'd0;
u_resource_apb4_if.pprot = 3'd0;
u_resource_apb4_if.psel = 1'b0;
u_resource_apb4_if.penable = 1'b0;
u_resource_apb4_if.pwrite = 1'b0;
u_resource_apb4_if.pwdata = 32'd0;
u_resource_apb4_if.pstrb = 4'd0;
u_plic_apb4_if.paddr = 32'd0;
u_plic_apb4_if.pprot = 3'd0;
u_plic_apb4_if.psel = 1'b0;
u_plic_apb4_if.penable = 1'b0;
u_plic_apb4_if.pwrite = 1'b0;
u_plic_apb4_if.pwdata = 32'd0;
u_plic_apb4_if.pstrb = 4'd0;
end
endtask
task automatic apu_write(input logic [11:0] offset_i, input logic [31:0] data_i);
begin
@(negedge clk_i);
u_apu_apb4_if.paddr = ApuBase + offset_i;
u_apu_apb4_if.pwdata = data_i;
u_apu_apb4_if.pstrb = 4'hf;
u_apu_apb4_if.pwrite = 1'b1;
u_apu_apb4_if.psel = 1'b1;
u_apu_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_apu_apb4_if.penable = 1'b1;
while (!u_apu_apb4_if.pready) @(negedge clk_i);
if (u_apu_apb4_if.pslverr) $fatal(1, "APU topology write failed at %h", offset_i);
@(negedge clk_i);
u_apu_apb4_if.psel = 1'b0;
u_apu_apb4_if.penable = 1'b0;
u_apu_apb4_if.pwrite = 1'b0;
u_apu_apb4_if.pstrb = 4'd0;
end
endtask
task automatic resource_write(input logic [11:0] offset_i, input logic [31:0] data_i,
input logic expected_err_i);
begin
@(negedge clk_i);
u_resource_apb4_if.paddr = {20'd0, offset_i};
u_resource_apb4_if.pwdata = data_i;
u_resource_apb4_if.pstrb = 4'hf;
u_resource_apb4_if.pwrite = 1'b1;
u_resource_apb4_if.psel = 1'b1;
u_resource_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_resource_apb4_if.penable = 1'b1;
while (!u_resource_apb4_if.pready) @(negedge clk_i);
if (u_resource_apb4_if.pslverr != expected_err_i) begin
$fatal(1, "Resource topology write response mismatch at %h", offset_i);
end
@(negedge clk_i);
u_resource_apb4_if.psel = 1'b0;
u_resource_apb4_if.penable = 1'b0;
u_resource_apb4_if.pwrite = 1'b0;
u_resource_apb4_if.pstrb = 4'd0;
end
endtask
task automatic plic_write(input logic [25:0] offset_i, input logic [31:0] data_i);
begin
@(negedge clk_i);
u_plic_apb4_if.paddr = {6'd0, offset_i};
u_plic_apb4_if.pwdata = data_i;
u_plic_apb4_if.pstrb = 4'hf;
u_plic_apb4_if.pwrite = 1'b1;
u_plic_apb4_if.psel = 1'b1;
u_plic_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_plic_apb4_if.penable = 1'b1;
while (!u_plic_apb4_if.pready) @(negedge clk_i);
if (u_plic_apb4_if.pslverr) $fatal(1, "PLIC topology write failed at %h", offset_i);
@(negedge clk_i);
u_plic_apb4_if.psel = 1'b0;
u_plic_apb4_if.penable = 1'b0;
u_plic_apb4_if.pwrite = 1'b0;
u_plic_apb4_if.pstrb = 4'd0;
end
endtask
task automatic plic_read(input logic [25:0] offset_i, output logic [31:0] data_o);
begin
@(negedge clk_i);
u_plic_apb4_if.paddr = {6'd0, offset_i};
u_plic_apb4_if.pstrb = 4'd0;
u_plic_apb4_if.pwrite = 1'b0;
u_plic_apb4_if.psel = 1'b1;
u_plic_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_plic_apb4_if.penable = 1'b1;
while (!u_plic_apb4_if.pready) @(negedge clk_i);
if (u_plic_apb4_if.pslverr) $fatal(1, "PLIC topology read failed at %h", offset_i);
data_o = u_plic_apb4_if.prdata;
@(negedge clk_i);
u_plic_apb4_if.psel = 1'b0;
u_plic_apb4_if.penable = 1'b0;
end
endtask
initial begin
drive_apb_idle();
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
plic_write(26'h000028, 32'd3);
plic_write(26'h002000, 32'h0000_0400);
plic_write(26'h200000, 32'd0);
apu_write(`APB4_APU__IRQ_ENABLE, 32'h0000_0001);
apu_write(`APB4_APU__IRQ_TEST, 32'h0000_0001);
repeat (2) @(posedge clk_i);
#1;
if ((s_resource_owner[7] != 2'd0) || !s_resource_irq_lp[7] || s_resource_irq_hp[7] ||
!s_apb4_periph_irq[23] || !s_irq[31] || s_hp_plic_source[10] ||
s_hp_plic_context_irq[0]) begin
$fatal(1, "APU event was not delivered exclusively to LP IRQ31");
end
resource_write(Resource7Control, 32'h0000_0001, 1'b0);
resource_write(Resource7Owner, 32'h0000_0101, 1'b0);
repeat (2) @(posedge clk_i);
#1;
if ((s_resource_owner[7] != 2'd1) || !s_resource_owner_lock[7] ||
s_resource_irq_lp[7] || !s_resource_irq_hp[7] || s_apb4_periph_irq[23] ||
s_irq[31] || !s_hp_plic_source[10] || !s_hp_plic_context_irq[0]) begin
$fatal(1, "APU event was not delivered exclusively to HP PLIC source 10");
end
plic_read(26'h200004, s_value);
if (s_value != 32'd10) $fatal(1, "HP PLIC did not claim APU source 10");
resource_write(Resource7Owner, 32'd0, 1'b1);
if ((s_resource_owner[7] != 2'd1) || !s_resource_owner_lock[7] || !s_resource_fault_irq) begin
$fatal(1, "APU owner lock did not preserve HP ownership");
end
resource_write(Resource7Fault, 32'h0000_0001, 1'b0);
if (s_resource_fault_irq) $fatal(1, "APU resource fault did not clear");
resource_write(Resource7Control, 32'h0000_0003, 1'b0);
repeat (2) @(posedge clk_i);
#1;
if (s_resource_irq_lp[7] || s_resource_irq_hp[7] || s_apb4_periph_irq[23] || s_irq[31] ||
s_hp_plic_source[10]) begin
$fatal(1, "APU resource reset did not mask both interrupt routes");
end
if (s_resource_fault_irq || s_cache_clean) begin
$fatal(1, "APU topology test left an unrelated controller output asserted");
end
$display("APU-P1 integrated IRQ ownership topology passed");
$finish;
end
initial begin
repeat (1000) @(posedge clk_i);
$fatal(1, "APU-P1 IRQ ownership topology timed out");
end
endmodule