2 Copyright (c) 2013, IIT Madras
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
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.
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 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
16 import defined_types::*;
19 import AXI4_Lite_Types::*;
23 `include "instance_defines.bsv"
25 `define INTERRUPT_LEVELS 8
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 :
43 Interrupt priority registers :
44 rg_priority_0 : 0C000000
45 rg_priority_1 : 0C000002
46 rg_priority_2 : 0C000004
50 Priority Threshold register :
51 rg_priority_threshold : 0C200000
53 rg_interrupt_id : 0C200004
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;
65 //(*conflict_free = "rl_prioritise, prog_reg"*)
66 module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins,no_of_ir_levels))
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),
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);
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)
101 rg_ie[i] = readOnlyReg(True);
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)
107 rg_priority_low[i] = readOnlyReg(1);
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();
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)
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
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;
143 if(lv_total_priority!=0) begin
144 rg_total_priority <= lv_total_priority;
146 Bit#(no_of_ir_levels) lv_winner_priority = 0;
147 lv_winner_priority[winner_priority] = 1;
148 rg_winner_priority <= lv_winner_priority;
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);
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)
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);
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;
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];
188 // for(Integer i=0;i<tree_ir;i=i+1) begin
189 // level_encoder[i] = any_req(lv_priority_ip[i]);
191 // for(Integer i=0;i<-tree_ir;i=i+1) begin
192 // ir_encoded[i] = encoder(priority_encoder(lv_priority_ip));
194 // for(Integer i=0;i<-tree_ir;i=i+1) begin
195 // rg_prioritized_encoded <= ir_encoded;
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)
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);
215 Vector#(no_of_ir_pins, Ifc_global_interrupt) temp_ifc_irq;
217 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin
219 temp_ifc_irq[i] = interface Ifc_global_interrupt
221 method Action irq_frm_gateway(Bool ir);
222 `ifdef verbose $display("Interrupt id %d is pending", i);`endif
229 interface ifc_external_irq = temp_ifc_irq;
231 interface ifc_prog_reg = interface Ifc_program_registers;
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]);
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];
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);
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]);
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]);
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
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]);
291 else if(address == 'hC200000) begin
292 if(mem_req.ld_st == Load) begin
293 data_return = zeroExtend(rg_priority_threshold);
295 else if(mem_req.ld_st == Store)
296 rg_priority_threshold <= mem_req.write_data[v_msb_priority:0];
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
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
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;
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);
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;
338 //(*conflict_free="rl_config_plic_reg_write,intrpt_completion"*)
339 module mkplicperipheral(Ifc_PLIC_AXI);
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();
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
352 byte_offset=fromInteger(i);
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);
360 rule rl_config_plic_reg_read;
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});
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]);
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);
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;