`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