|
| 1 | +// Corrected Virtual PLIC interface for Verilator simulation |
| 2 | +module plicdpi #( |
| 3 | + parameter int SOURCES = 32, |
| 4 | + parameter int TARGETS = 1, |
| 5 | + parameter int PRIORITIES = 3 |
| 6 | +)( |
| 7 | + input logic clk_i, |
| 8 | + input logic rst_ni, |
| 9 | + |
| 10 | + // Bus interface signals (matching the RTL plic register map) |
| 11 | + input logic req_i, |
| 12 | + input logic [31:0] addr_i, |
| 13 | + input logic we_i, |
| 14 | + input logic [3:0] be_i, |
| 15 | + input logic [31:0] wdata_i, |
| 16 | + output logic rvalid_o, |
| 17 | + output logic [31:0] rdata_o, |
| 18 | + |
| 19 | + // Interrupt interface |
| 20 | + input logic [SOURCES-1:0] irq_sources_i, |
| 21 | + output logic [SOURCES-1:0] irq_pending_o, |
| 22 | + output logic [TARGETS-1:0] irq_o |
| 23 | +); |
| 24 | + |
| 25 | + // Register map constants (same as in plic.sv) |
| 26 | + localparam int PRIORITY_BASE = 'h000000; |
| 27 | + localparam int PENDING_BASE = 'h001000; |
| 28 | + localparam int ENABLE_BASE = 'h002000; |
| 29 | + localparam int THRESHOLD_BASE = 'h200000; |
| 30 | + localparam int CLAIM_COMPLETE = 'h200004; |
| 31 | + |
| 32 | + // Internal registers |
| 33 | + logic [PRIORITIES-1:0] priorities [SOURCES]; |
| 34 | + logic [SOURCES-1:0] enables; |
| 35 | + logic [PRIORITIES-1:0] threshold; |
| 36 | + logic [SOURCES-1:0] pending; |
| 37 | + logic [$clog2(SOURCES)-1:0] claimed_irq; |
| 38 | + |
| 39 | + // Register interface read data |
| 40 | + logic [31:0] reg_rdata; |
| 41 | + |
| 42 | + // ------------------------------ |
| 43 | + // Write Handling |
| 44 | + // ------------------------------ |
| 45 | + always_ff @(posedge clk_i or negedge rst_ni) begin |
| 46 | + if (!rst_ni) begin |
| 47 | + for (int i = 0; i < SOURCES; i++) begin |
| 48 | + priorities[i] <= '0; |
| 49 | + end |
| 50 | + enables <= '0; |
| 51 | + threshold <= '0; |
| 52 | + end else if (req_i && we_i) begin |
| 53 | + case (addr_i[15:12]) |
| 54 | + 5'h0: begin // Priority registers |
| 55 | + if (addr_i[11:2] < SOURCES) |
| 56 | + priorities[addr_i[11:2]] <= wdata_i[PRIORITIES-1:0]; |
| 57 | + end |
| 58 | + 5'h2: begin // Enable registers |
| 59 | + if (addr_i[11:2] == 0) |
| 60 | + enables <= wdata_i[SOURCES-1:0]; |
| 61 | + end |
| 62 | + 5'h20: begin // Threshold and claim/complete region |
| 63 | + if (addr_i[3:2] == 0) |
| 64 | + threshold <= wdata_i[PRIORITIES-1:0]; |
| 65 | + else if (addr_i[3:2] == 1) begin |
| 66 | + // Handle interrupt completion: clear pending bit for the given IRQ index |
| 67 | + if (wdata_i < SOURCES) |
| 68 | + pending[wdata_i] <= 1'b0; |
| 69 | + end |
| 70 | + end |
| 71 | + default: ; |
| 72 | + endcase |
| 73 | + end |
| 74 | + end |
| 75 | + |
| 76 | + // ------------------------------ |
| 77 | + // Read Handling |
| 78 | + // ------------------------------ |
| 79 | + always_comb begin |
| 80 | + reg_rdata = '0; |
| 81 | + case (addr_i[15:12]) |
| 82 | + 5'h0: begin // Priority registers |
| 83 | + if (addr_i[11:2] < SOURCES) |
| 84 | + reg_rdata = {{(32-PRIORITIES){1'b0}}, priorities[addr_i[11:2]]}; |
| 85 | + end |
| 86 | + 5'h1: begin // Pending registers |
| 87 | + if (addr_i[11:2] == 0) |
| 88 | + reg_rdata = pending; |
| 89 | + end |
| 90 | + 5'h2: begin // Enable registers |
| 91 | + if (addr_i[11:2] == 0) |
| 92 | + reg_rdata = enables; |
| 93 | + end |
| 94 | + 5'h20: begin // Threshold and claim/complete region |
| 95 | + if (addr_i[3:2] == 0) |
| 96 | + reg_rdata = {{(32-PRIORITIES){1'b0}}, threshold}; |
| 97 | + else if (addr_i[3:2] == 1) |
| 98 | + reg_rdata = claimed_irq; |
| 99 | + end |
| 100 | + default: reg_rdata = '0; |
| 101 | + endcase |
| 102 | + end |
| 103 | + |
| 104 | + // ------------------------------ |
| 105 | + // Interrupt Pending Update |
| 106 | + // ------------------------------ |
| 107 | + always_ff @(posedge clk_i or negedge rst_ni) begin |
| 108 | + if (!rst_ni) |
| 109 | + pending <= '0; |
| 110 | + else begin |
| 111 | + for (int i = 0; i < SOURCES; i++) begin |
| 112 | + if (irq_sources_i[i] && enables[i]) |
| 113 | + pending[i] <= 1'b1; |
| 114 | + end |
| 115 | + end |
| 116 | + end |
| 117 | + |
| 118 | + // ------------------------------ |
| 119 | + // Highest-Priority Pending Interrupt Logic |
| 120 | + // ------------------------------ |
| 121 | + always_comb begin |
| 122 | + logic found_irq; |
| 123 | + logic [$clog2(SOURCES)-1:0] highest_irq; |
| 124 | + logic [PRIORITIES-1:0] highest_priority; |
| 125 | + |
| 126 | + found_irq = 1'b0; |
| 127 | + highest_irq = '0; |
| 128 | + highest_priority = '0; |
| 129 | + |
| 130 | + for (int i = 0; i < SOURCES; i++) begin |
| 131 | + if (pending[i] && enables[i] && (priorities[i] > threshold) && |
| 132 | + (!found_irq || priorities[i] > highest_priority)) begin |
| 133 | + found_irq = 1'b1; |
| 134 | + highest_irq = i; |
| 135 | + highest_priority = priorities[i]; |
| 136 | + end |
| 137 | + end |
| 138 | + |
| 139 | + claimed_irq = highest_irq; |
| 140 | + irq_o = found_irq; |
| 141 | + end |
| 142 | + |
| 143 | + assign irq_pending_o = pending; |
| 144 | + |
| 145 | + // ------------------------------ |
| 146 | + // Response Valid Signal |
| 147 | + // ------------------------------ |
| 148 | + always_ff @(posedge clk_i or negedge rst_ni) begin |
| 149 | + if (!rst_ni) |
| 150 | + rvalid_o <= 1'b0; |
| 151 | + else |
| 152 | + rvalid_o <= req_i; |
| 153 | + end |
| 154 | + |
| 155 | + assign rdata_o = reg_rdata; |
| 156 | + |
| 157 | +endmodule |
0 commit comments