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_parameters::*;
17 import defined_types::*;
20 import AXI4_Lite_Types::*;
23 `include "instance_defines.bsv"
24 // import ConfigReg::*;
25 /*Platform level interrupt controller:
26 Refer to RISC-V privilege spec-v-1.10 chapter 7
27 Memory maps of Registers
28 Interrupt enable registers :
40 Interrupt priority registers :
41 rg_priority_0 : 0C000000
42 rg_priority_1 : 0C000002
43 rg_priority_2 : 0C000004
47 Priority Threshold register :
48 rg_priority_threshold : 0C200000
50 rg_interrupt_id : 0C200004
54 interface Ifc_PLIC#(numeric type addr_width,numeric type word_size,numeric type no_of_ir_pins);
55 interface Vector#(no_of_ir_pins,Ifc_global_interrupt) ifc_external_irq;
56 interface Ifc_program_registers#(addr_width,word_size) ifc_prog_reg;
57 method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note;
58 method ActionValue#(Bit#(TLog#(no_of_ir_pins))) intrpt_completion;
61 //(*conflict_free = "rl_prioritise, prog_reg"*)
62 module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins))
64 Log#(no_of_ir_pins, priority_bits),
65 Mul#(8,word_size,data_width),
66 Add#(1,priority_bits,x_priority_bits),
67 Add#(msb_priority,1,priority_bits),
68 Add#(msb_priority_bits,1,no_of_ir_pins),
69 Add#(b__, no_of_ir_pins, data_width),
70 Add#(c__, priority_bits, data_width),
71 Add#(a__, 8, no_of_ir_pins),
72 Add#(e__, 32, data_width),
73 Add#(g__, 32, no_of_ir_pins),
74 Add#(f__, 3, priority_bits),
75 Add#(d__, 5, priority_bits)
77 let v_no_of_ir_pins = valueOf(no_of_ir_pins);
78 let v_priority_bits = valueOf(priority_bits);
79 let v_msb_priority_bits = valueOf(msb_priority_bits);
80 let v_msb_priority = valueOf(msb_priority);
81 let v_data_width = valueOf(data_width);
85 /* This function defines the working of priority encoder with 4 bit inputs */
86 function Bit#(8) priority_encoder(Bit#(8) inp, Bool alu_free);
110 function bit any_req(Bit#(8) inp);
111 return inp[0] | inp[1] | inp[2] | inp[3] | inp[4] | inp[5] | inp[6] | inp[7];
114 /* Encodes the grant vector */
115 function Bit#(x_priority_bits) encoder(Bit#(no_of_ir_pins) inp);
116 Bit#(priority_bits) outp = 0;
117 bit outp_valid = 1'b1;
118 for(Integer i = 0; i < v_no_of_ir_pins; i = i+1) begin
120 outp = fromInteger(i);
122 return {outp_valid,outp};
125 function Reg#(t) readOnlyReg(t r);
126 return (interface Reg;
128 method Action _write(t x) = noAction;
132 /* Request vectors are passed down the tree and the grants are given back */
133 function Bit#(no_of_ir_pins) encoder_tree(Bit#(no_of_ir_pins) inp);
134 Bit#(no_of_ir_pins) outp = 0;
141 for(Integer i=0;i<8;i=i+1)
142 root_reqs[i] = any_req(inp[8*fromInteger(i)+7:8*fromInteger(i)]);
144 root_grants = priority_encoder(root_reqs, True);
146 //grants are passed back to leaves
147 for(Integer i=0;i<8;i=i+1)
148 outp[8*fromInteger(i)+7:8*fromInteger(i)] = priority_encoder(inp[8*fromInteger(i)+7:8*fromInteger(i)], unpack(root_grants[i]));
152 Vector#(no_of_ir_pins,Array#(Reg#(Bool))) rg_ip <- replicateM(mkCReg(2,False));
153 Reg#(Bool) rg_ie[v_no_of_ir_pins];
154 for(Integer i = 0; i < v_no_of_ir_pins;i=i+1)
156 rg_ie[i] = readOnlyReg(True);
158 rg_ie[i] <- mkReg(False);
159 Reg#(Bit#(32)) rg_priority_low[v_no_of_ir_pins];
160 for(Integer i =0; i < v_no_of_ir_pins; i=i+1)
162 rg_priority_low[i] = readOnlyReg(32'h00000001);
164 rg_priority_low[i] <- mkConfigReg(0);
165 Reg#(Bit#(no_of_ir_pins)) rg_priority[v_no_of_ir_pins];
166 for(Integer i=0;i < v_no_of_ir_pins;i=i+1)
167 rg_priority[i] = concatReg2(readOnlyReg(0), rg_priority_low[i]);
168 Reg#(Bit#(5)) rg_priority_threshold_low <- mkReg(0);
169 Reg#(Bit#(priority_bits)) rg_priority_threshold = concatReg2(readOnlyReg(0),rg_priority_threshold_low);
170 Reg#(Bit#(priority_bits)) rg_interrupt_id <- mkConfigReg(0);
171 Reg#(Bool) rg_interrupt_valid <- mkConfigReg(False);
172 Reg#(Maybe#(Bit#(priority_bits))) rg_completion_id <- mkReg(tagged Invalid);
175 Bit#(priority_bits) winner_priority = 0;
176 Bit#(priority_bits) winner_interrupts = 0;
177 Bit#(x_priority_bits) ir_id_valid = 0;
178 Bit#(no_of_ir_pins) lv_priority = 0;
179 Bit#(no_of_ir_pins) lv_total_priority = 0;
180 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1)
183 if(rg_ip[i][1] && rg_ie[i]) begin
184 lv_priority = lv_priority | rg_priority[i];
185 winner_interrupts = fromInteger(i);
186 `ifdef verbose $display($time,"\tInterrupt id %d and priority is %d", i, lv_priority);`endif
189 winner_priority = encoder(encoder_tree(lv_priority))[v_msb_priority:0];
190 `ifdef verbose $display($time,"\t winner priority is %d", winner_priority);`endif
191 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin
192 if(rg_priority[i][winner_priority] == 1 && rg_ip[i][1] && rg_ie[i])
193 lv_total_priority[i] = 1;
195 if(lv_total_priority!=0)
196 winner_interrupts = encoder(encoder_tree(lv_total_priority))[v_msb_priority:0];
197 if(winner_interrupts!=0) begin
198 ir_id_valid = encoder(rg_priority[winner_interrupts]);
199 if(winner_priority <= rg_priority_threshold)
202 `ifdef verbose $display("Interrupt valid");`endif
203 rg_interrupt_id <= winner_interrupts;
204 rg_interrupt_valid <= True;
205 $display($time,"\t The highest priority interrupt is %d and the priority is ", winner_interrupts, winner_priority);
210 Vector#(no_of_ir_pins, Ifc_global_interrupt) temp_ifc_irq;
212 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin
214 temp_ifc_irq[i] = interface Ifc_global_interrupt
216 method Action irq_frm_gateway(Bool ir);
217 `ifdef verbose $display("Interrupt id %d is pending", i);`endif
224 interface ifc_external_irq = temp_ifc_irq;
226 interface ifc_prog_reg = interface Ifc_program_registers;
228 method ActionValue#(Bit#(data_width)) prog_reg(UncachedMemReq#(addr_width, word_size) mem_req);
229 //update memory mapped registers
230 `ifdef verbose $display($time,"\tPLIC : programming registers for address %h", mem_req.address);`endif
231 let address = mem_req.address;
232 Bit#(priority_bits) source_id=0;
233 Bit#(data_width) data_return = 0;
234 // if(address < 'h0C001000) begin
235 if (address < `PLICBase + 'h1000)begin
236 address = address >> 2;
237 if(mem_req.ld_st == Load) begin
238 source_id = address[v_msb_priority:0];
239 `ifdef verbose $display($time,"\tPLIC : source %d Priority set to %h", source_id, mem_req.write_data);`endif
240 data_return = zeroExtend(rg_priority[source_id]);
242 else if(mem_req.ld_st == Store) begin
243 Bit#(no_of_ir_pins) store_data;
244 if(mem_req.byte_offset==0)
245 store_data=mem_req.write_data[v_msb_priority_bits:0];
247 store_data=mem_req.write_data[v_data_width-1:v_data_width-v_no_of_ir_pins];
248 mem_req.byte_offset = mem_req.byte_offset >> 2;
249 source_id = address[v_msb_priority:0] | zeroExtend(mem_req.byte_offset);
250 $display($time,"\tPLIC : source %d Priority set to %h", source_id, store_data);
251 rg_priority[source_id] <= store_data;
254 //else if(address < 'h0C002000) begin
255 else if(address<`PLICBase+'h2000)begin
256 if(mem_req.ld_st == Load) begin
257 source_id = address[v_msb_priority:0];
258 source_id = source_id << 3;
259 for(Integer i = 0; i < 8; i = i+1)
260 data_return[i] = pack(rg_ip[source_id + fromInteger(i)][1]);
262 else if(mem_req.ld_st == Store) begin
263 source_id = zeroExtend(mem_req.byte_offset);
264 source_id = source_id << 3;
265 for(Integer i = 0; i < 8; i = i+1) begin
266 `ifdef verbose $display($time,"\tPLIC : pending interrupt %b id %d", mem_req.write_data[i], source_id);`endif
267 rg_ip[source_id + fromInteger(i)][1] <= unpack(mem_req.write_data[i]);
271 //else if(address < 'h0C020000) begin
272 else if(address < `PLICBase+'h20000)begin
273 if(mem_req.ld_st == Load) begin
274 source_id = address[v_msb_priority:0];
275 source_id = source_id << 3;
276 for(Integer i = 0; i < 8; i = i+1)
277 data_return[i] = pack(rg_ie[source_id + fromInteger(i)]);
278 `ifdef verbose $display($time,"PLIC: Printing Source Enable Interrupt: %h data_return: %h",source_id,data_return); `endif
280 else if(mem_req.ld_st == Store) begin
281 source_id = zeroExtend(mem_req.byte_offset);
282 source_id = source_id << 3;
283 for(Integer i = 0; i < 8; i = i+1) begin
284 `ifdef verbose $display($time,"\tPLIC : enabled interrupt %b id %d", mem_req.write_data[i], source_id);`endif
285 rg_ie[source_id + fromInteger(i)] <= unpack(mem_req.write_data[i]);
289 // else if(address == 'hC200000) begin
290 else if(address ==`PLICBase+'h200000)begin
291 if(mem_req.ld_st == Load) begin
292 data_return = zeroExtend(rg_priority_threshold);
294 else if(mem_req.ld_st == Store)
295 rg_priority_threshold <= mem_req.write_data[v_msb_priority:0];
297 // else if(address == 'hC200004) begin
298 else if(address == `PLICBase+'h200004)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_priority: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) 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});
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)
371 let r = AXI4_Lite_Rd_Data {rresp: AXI4_LITE_OKAY, rdata: duplicate(x), ruser: 0};
372 s_xactor_plic.i_rd_data.enq(r);
375 interface axi4_slave_plic = s_xactor_plic.axi_side;
376 interface ifc_external_irq = plic.ifc_external_irq;
377 method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note = plic.intrpt_note;
378 method ActionValue#(Bit#(TLog#(`INTERRUPT_PINS))) intrpt_completion = plic.intrpt_completion;