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+ 4'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+ 4'h2 : begin // Enable registers
65+ if (addr_i[11 : 2 ] == 0 ) enables <= wdata_i[SOURCES - 1 : 0 ];
66+ end
67+ 4'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+ 4'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+ 4'h1 : begin // Pending registers
89+ if (addr_i[11 : 2 ] == 0 ) reg_rdata = pending;
90+ end
91+ 4'h2 : begin // Enable registers
92+ if (addr_i[11 : 2 ] == 0 ) reg_rdata = enables;
93+ end
94+ 4'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