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