PLIC modified to support interrupts upto 1024
[shakti-peripherals.git] / src / peripherals / plic / plic.bsv
1 /*
2 Copyright (c) 2013, IIT Madras
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 * Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
13 */
14 package plic;
15 import Vector::*;
16 import defined_types::*;
17 import ConfigReg::*;
18 import Semi_FIFOF::*;
19 import AXI4_Lite_Types::*;
20 import BUtils ::*;
21 import ConcatReg ::*;
22 import encoder ::*;
23 `include "instance_defines.bsv"
24
25 `define INTERRUPT_LEVELS 8
26
27 // import ConfigReg::*;
28 /*Platform level interrupt controller:
29 Refer to RISC-V privilege spec-v-1.10 chapter 7
30 Memory maps of Registers
31 Interrupt enable registers :
32 rg_ie_0 :0C002000
33 rg_ie_1 :0C002000
34 rg_ie_2 :0C002000
35 .
36 .
37 .
38 rg_ie_7 :0C002000
39 rg_ie_8 :0C002001
40 rg_ie_9 :0C002001
41 .
42 .
43 Interrupt priority registers :
44 rg_priority_0 : 0C000000
45 rg_priority_1 : 0C000002
46 rg_priority_2 : 0C000004
47 .
48 .
49 .
50 Priority Threshold register :
51 rg_priority_threshold : 0C200000
52 Claim register :
53 rg_interrupt_id : 0C200004
54 */
55
56
57 interface Ifc_PLIC#(numeric type addr_width,numeric type word_size,numeric type no_of_ir_pins,
58 numeric type no_of_ir_levels);
59 interface Vector#(no_of_ir_pins,Ifc_global_interrupt) ifc_external_irq;
60 interface Ifc_program_registers#(addr_width,word_size) ifc_prog_reg;
61 method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note;
62 method ActionValue#(Bit#(TLog#(no_of_ir_pins))) intrpt_completion;
63 endinterface
64
65 //(*conflict_free = "rl_prioritise, prog_reg"*)
66 module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins,no_of_ir_levels))
67 provisos(
68 Log#(no_of_ir_pins, ir_bits),
69 Log#(no_of_ir_levels, priority_bits),
70 Mul#(8,word_size,data_width),
71 //Mul#(3,no_iterations,ir_bits),
72 Add#(1,ir_bits,x_ir_bits),
73 Add#(msb_ir_bits,1,ir_bits),
74 Add#(msb_ir_pins,1,no_of_ir_pins),
75 Add#(msb_priority_levels,1,no_of_ir_levels),
76 Add#(msb_priority_bits,1,priority_bits),
77 Add#(a__, no_of_ir_levels, data_width),
78 Add#(b__, ir_bits, data_width),
79 Add#(c__, no_of_ir_pins, 1024),
80 Add#(d__, ir_bits, 10),
81 Add#(f__, no_of_ir_levels, 1024),
82 Add#(g__, priority_bits, 10),
83 Add#(h__, no_of_ir_levels, 32),
84 Add#(e__, 32, data_width)
85 //Mul#(no_iterations, 3, ir_bits),
86 );
87 let v_no_of_ir_pins = valueOf(no_of_ir_pins);
88 let v_ir_bits = valueOf(ir_bits);
89 let v_msb_ir_bits = valueOf(msb_ir_bits);
90 let v_msb_ir_pins = valueOf(msb_ir_pins);
91 let v_msb_priority = valueOf(msb_priority_levels);
92 let v_data_width = valueOf(data_width);
93
94 //(* noinline *)
95
96
97 Vector#(no_of_ir_pins,Array#(Reg#(Bool))) rg_ip <- replicateM(mkCReg(2,False));
98 Reg#(Bool) rg_ie[v_no_of_ir_pins];
99 for(Integer i = 0; i < v_no_of_ir_pins;i=i+1)
100 if(i==28 || i == 29)
101 rg_ie[i] = readOnlyReg(True);
102 else
103 rg_ie[i] <- mkReg(False);
104 Reg#(Bit#(no_of_ir_levels)) rg_priority_low[v_no_of_ir_pins];
105 for(Integer i =0; i < v_no_of_ir_pins; i=i+1)
106 if(i==28 || i == 29)
107 rg_priority_low[i] = readOnlyReg(1);
108 else
109 rg_priority_low[i] <- mkConfigReg(0);
110 Reg#(Bit#(32)) rg_priority[v_no_of_ir_pins];
111 for(Integer i=0;i < v_no_of_ir_pins;i=i+1)
112 rg_priority[i] = concatReg2(readOnlyReg(0), rg_priority_low[i]);
113 Reg#(Bit#(no_of_ir_levels)) rg_priority_threshold <- mkReg(0);
114 Reg#(Bit#(ir_bits)) rg_interrupt_id <- mkConfigReg(0);
115 Reg#(Bool) rg_interrupt_valid <- mkConfigReg(False);
116 Reg#(Maybe#(Bit#(ir_bits))) rg_completion_id <- mkReg(tagged Invalid);
117 Reg#(Bit#(no_of_ir_pins)) rg_total_priority <- mkReg(0);
118 Reg#(Bit#(1)) rg_plic_state <- mkReg(0); //TODO put an enum later
119 Reg#(Bit#(no_of_ir_levels)) rg_winner_priority <- mkReg(0);
120 Ifc_encoder#(no_of_ir_levels) ir_priority_encoder <- mkencoder();
121 Ifc_encoder#(no_of_ir_pins) irencoder <- mkencoder();
122
123 rule rl_prioritise(rg_plic_state==0);
124 Bit#(priority_bits) winner_priority = 0;
125 Bit#(ir_bits) winner_interrupts = 0;
126 Bit#(x_ir_bits) ir_id_valid = 0;
127 Bit#(no_of_ir_levels) lv_priority = 0;
128 Bit#(no_of_ir_pins) lv_total_priority = 0;
129 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1)
130 begin
131
132 if(rg_ip[i][1] && rg_ie[i]) begin
133 lv_priority = lv_priority | truncate(rg_priority[i]);
134 `ifdef verbose $display($time,"\tInterrupt id %d and priority is %d", i, lv_priority);`endif
135 end
136 end
137 winner_priority = ir_priority_encoder.encode(lv_priority);
138 `ifdef verbose $display($time,"\t winner priority is %d", winner_priority);`endif
139 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin
140 if(rg_priority[i][winner_priority] == 1 && rg_ip[i][1] && rg_ie[i])
141 lv_total_priority[i] = 1;
142 end
143 if(lv_total_priority!=0) begin
144 rg_total_priority <= lv_total_priority;
145 rg_plic_state <= 1;
146 Bit#(no_of_ir_levels) lv_winner_priority = 0;
147 lv_winner_priority[winner_priority] = 1;
148 rg_winner_priority <= lv_winner_priority;
149 end
150 endrule
151
152 rule rl_encoder(rg_plic_state==1);
153 Bit#(ir_bits) interrupt_id = irencoder.encode(rg_total_priority);
154 if(interrupt_id!=0 && rg_priority_threshold >= rg_winner_priority) begin
155 `ifdef verbose $display("Interrupt valid");`endif
156 rg_interrupt_id <= interrupt_id;
157 rg_interrupt_valid <= True;
158 $display($time,"\t The highest priority interrupt is %d and the priority is ", interrupt_id, rg_winner_priority);
159 end
160 rg_plic_state <= 0;
161
162
163 //if(lv_total_priority!=0)
164 //winner_interrupts = encoder(encoder_tree(lv_total_priority))[v_msb_priority:0];
165 //if(winner_interrupts!=0) begin
166 // if(winner_priority <= rg_priority_threshold)
167 // begin
168 //
169 // `ifdef verbose $display("Interrupt valid");`endif
170 // rg_interrupt_id <= winner_interrupts;
171 // rg_interrupt_valid <= True;
172 // $display($time,"\t The highest priority interrupt is %d and the priority is ", winner_interrupts, winner_priority);
173 // end
174 //end
175 endrule
176
177
178 //for(Integer i = 0; i<no_iterations; i=i+1) begin
179 // rule rl_encoder(rg_plic_state==1);
180 // Bit#(no_of_ir_pins) lv_total_priority = rg_total_priority;
181 // Vector#(tree_ir, Bit#(8)) lv_priority_ip;
182 // Bit#(tree_ir) level_encoder;
183 // Vector#(tree_ir, 3) ir_encoded;
184 //
185 // for(Integer i=0;i<tree_ir;i=i+1) begin
186 // lv_priority_ip[i]=lv_total_priority[i*8+7:i*8];
187 // end
188 // for(Integer i=0;i<tree_ir;i=i+1) begin
189 // level_encoder[i] = any_req(lv_priority_ip[i]);
190 // end
191 // for(Integer i=0;i<-tree_ir;i=i+1) begin
192 // ir_encoded[i] = encoder(priority_encoder(lv_priority_ip));
193 // end
194 // for(Integer i=0;i<-tree_ir;i=i+1) begin
195 // rg_prioritized_encoded <= ir_encoded;
196 // end
197 //
198 //
199 // //if(lv_total_priority!=0)
200 // //winner_interrupts = encoder(encoder_tree(lv_total_priority))[v_msb_priority:0];
201 // //if(winner_interrupts!=0) begin
202 // // ir_id_valid = encoder(rg_priority[winner_interrupts]);
203 // // if(winner_priority <= rg_priority_threshold)
204 // // begin
205 // //
206 // // `ifdef verbose $display("Interrupt valid");`endif
207 // // rg_interrupt_id <= winner_interrupts;
208 // // rg_interrupt_valid <= True;
209 // // $display($time,"\t The highest priority interrupt is %d and the priority is ", winner_interrupts, winner_priority);
210 // // end
211 // //end
212 // endrule
213 //end
214
215 Vector#(no_of_ir_pins, Ifc_global_interrupt) temp_ifc_irq;
216
217 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin
218
219 temp_ifc_irq[i] = interface Ifc_global_interrupt
220
221 method Action irq_frm_gateway(Bool ir);
222 `ifdef verbose $display("Interrupt id %d is pending", i);`endif
223 rg_ip[i][0] <= True;
224 endmethod
225
226 endinterface;
227 end
228
229 interface ifc_external_irq = temp_ifc_irq;
230
231 interface ifc_prog_reg = interface Ifc_program_registers;
232
233 method ActionValue#(Bit#(data_width)) prog_reg(UncachedMemReq#(addr_width, word_size) mem_req);
234 //update memory mapped registers
235 `ifdef verbose $display($time,"\tPLIC : programming registers for address %h", mem_req.address);`endif
236 let address = mem_req.address;
237 Bit#(ir_bits) source_id=0;
238 Bit#(data_width) data_return = 0;
239 if(address < 'h0C001000) begin
240 address = address >> 2;
241 if(mem_req.ld_st == Load) begin
242 source_id = address[v_msb_ir_bits:0];
243 `ifdef verbose $display($time,"\tPLIC : source %d Priority set to %h", source_id, mem_req.write_data);`endif
244 data_return = zeroExtend(rg_priority[source_id]);
245 end
246 else if(mem_req.ld_st == Store) begin
247 Bit#(data_width) store_data;
248 if(mem_req.byte_offset==0)
249 store_data=mem_req.write_data[v_msb_ir_pins:0];
250 else
251 store_data=mem_req.write_data[v_data_width-1:v_data_width-v_no_of_ir_pins];
252 mem_req.byte_offset = mem_req.byte_offset >> 2;
253 source_id = address[v_msb_ir_bits:0];
254 $display($time,"\tPLIC : source %d Priority set to %h", source_id, store_data);
255 rg_priority[source_id] <= truncate(store_data);
256 end
257 end
258 else if(address < 'h0C002000) begin
259 if(mem_req.ld_st == Load) begin
260 source_id = address[v_msb_ir_bits:0];
261 source_id = source_id << 3;
262 for(Integer i = 0; i < 8; i = i+1)
263 data_return[i] = pack(rg_ip[source_id + fromInteger(i)][1]);
264 end
265 else if(mem_req.ld_st == Store) begin
266 source_id = address[v_msb_ir_bits:0];
267 source_id = source_id << 3;
268 for(Integer i = 0; i < 8; i = i+1) begin
269 `ifdef verbose $display($time,"\tPLIC : pending interrupt %b id %d", mem_req.write_data[i], source_id);`endif
270 rg_ip[source_id + fromInteger(i)][1] <= unpack(mem_req.write_data[i]);
271 end
272 end
273 end
274 else if(address < 'h0C020000) begin
275 if(mem_req.ld_st == Load) begin
276 source_id = address[v_msb_ir_bits:0];
277 source_id = source_id << 3;
278 for(Integer i = 0; i < 8; i = i+1)
279 data_return[i] = pack(rg_ie[source_id + fromInteger(i)]);
280 `ifdef verbose $display($time,"PLIC: Printing Source Enable Interrupt: %h data_return: %h",source_id,data_return); `endif
281 end
282 else if(mem_req.ld_st == Store) begin
283 source_id = address[v_msb_ir_bits:0];
284 source_id = source_id << 3;
285 for(Integer i = 0; i < 8; i = i+1) begin
286 `ifdef verbose $display($time,"\tPLIC : enabled interrupt %b id %d", mem_req.write_data[i], source_id);`endif
287 rg_ie[source_id + fromInteger(i)] <= unpack(mem_req.write_data[i]);
288 end
289 end
290 end
291 else if(address == 'hC200000) begin
292 if(mem_req.ld_st == Load) begin
293 data_return = zeroExtend(rg_priority_threshold);
294 end
295 else if(mem_req.ld_st == Store)
296 rg_priority_threshold <= mem_req.write_data[v_msb_priority:0];
297 end
298 else if(address == 'hC200004) begin
299 if(mem_req.ld_st == Load) begin
300 data_return = zeroExtend(rg_interrupt_id);
301 rg_ip[rg_interrupt_id][1] <= False;
302 `ifdef verbose $display($time,"rg_ip is made false here"); `endif
303 end
304 else if(mem_req.ld_st == Store) begin
305 source_id = mem_req.write_data[v_msb_ir_bits:0];
306 rg_completion_id <= tagged Valid source_id;
307 `ifdef verbose $display("rg_completion_id is made tagged valid and completion is signaled-- source_id: %d",source_id); `endif
308 end
309 end
310 return data_return;
311 endmethod
312
313 endinterface;
314
315 method ActionValue#(Bit#(TLog#(no_of_ir_pins))) intrpt_completion if(isValid(rg_completion_id));
316 let completion_msg = validValue(rg_completion_id);
317 rg_completion_id <= tagged Invalid;
318 `ifdef verbose $display("Sending Completion to SoC"); `endif
319 return completion_msg;
320 endmethod
321
322 method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note;
323 Bool if_nmi = (rg_interrupt_id == 28 || rg_interrupt_id == 29);
324 Bool valid_interrupt = rg_interrupt_valid;
325 rg_interrupt_valid <= False;
326 return tuple2(valid_interrupt, if_nmi);
327 endmethod
328 endmodule
329
330 interface Ifc_PLIC_AXI;
331 interface AXI4_Lite_Slave_IFC#(`PADDR, `Reg_width,`USERSPACE) axi4_slave_plic;
332 interface Vector#(`INTERRUPT_PINS,Ifc_global_interrupt) ifc_external_irq;
333 method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note;
334 method ActionValue#(Bit#(TLog#(`INTERRUPT_PINS))) intrpt_completion;
335 endinterface
336
337 (*synthesize*)
338 //(*conflict_free="rl_config_plic_reg_write,intrpt_completion"*)
339 module mkplicperipheral(Ifc_PLIC_AXI);
340
341 AXI4_Lite_Slave_Xactor_IFC #(`PADDR, `Reg_width, `USERSPACE) s_xactor_plic <- mkAXI4_Lite_Slave_Xactor;
342 Ifc_PLIC#(`PADDR, `DCACHE_WORD_SIZE, `INTERRUPT_PINS, `INTERRUPT_LEVELS) plic <- mkplic();
343
344 (*preempts="rl_config_plic_reg_read, rl_config_plic_reg_write"*)
345 rule rl_config_plic_reg_write;
346 let aw <- pop_o(s_xactor_plic.o_wr_addr);
347 let w <- pop_o(s_xactor_plic.o_wr_data);
348 let w_strobe = w.wstrb;
349 Bit#(3) byte_offset=0;
350 for(Integer i=7; i >= 0; i=i-1) begin
351 if(w_strobe[i]==1)
352 byte_offset=fromInteger(i);
353 end
354 let x <- plic.ifc_prog_reg.prog_reg(UncachedMemReq{address : aw.awaddr, transfer_size : 'd3,
355 u_signed : 0, byte_offset : byte_offset, write_data : w.wdata, ld_st : Store});
356 let w_resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_OKAY, buser: 0 }; //TODO user value is null
357 s_xactor_plic.i_wr_resp.enq(w_resp);
358 endrule
359
360 rule rl_config_plic_reg_read;
361
362 let ar <- pop_o(s_xactor_plic.o_rd_addr);
363 let x <- plic.ifc_prog_reg.prog_reg(UncachedMemReq{address : ar.araddr, transfer_size : 'd3,
364 u_signed : 0, byte_offset : 0, ld_st : Load});
365 if(ar.arsize==3'd0)
366 x = duplicate(x[7:0]);
367 else if(ar.arsize==3'd1)
368 x = duplicate(x[15:0]);
369 else if(ar.arsize==3'd2)
370 x = duplicate(x[7:0]);
371
372 let r = AXI4_Lite_Rd_Data {rresp: AXI4_LITE_OKAY, rdata: duplicate(x), ruser: 0};
373 s_xactor_plic.i_rd_data.enq(r);
374 endrule
375
376 interface axi4_slave_plic = s_xactor_plic.axi_side;
377 interface ifc_external_irq = plic.ifc_external_irq;
378 method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note = plic.intrpt_note;
379 method ActionValue#(Bit#(TLog#(`INTERRUPT_PINS))) intrpt_completion = plic.intrpt_completion;
380
381 endmodule
382 endpackage