0e94ee7bd7d075f37033ebdf68522a047d775ee1
[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_parameters::*;
17 import defined_types::*;
18 import ConfigReg::*;
19 import Semi_FIFOF::*;
20 import AXI4_Lite_Types::*;
21 import BUtils ::*;
22 import ConcatReg ::*;
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 :
29 rg_ie_0 :0C002000
30 rg_ie_1 :0C002000
31 rg_ie_2 :0C002000
32 .
33 .
34 .
35 rg_ie_7 :0C002000
36 rg_ie_8 :0C002001
37 rg_ie_9 :0C002001
38 .
39 .
40 Interrupt priority registers :
41 rg_priority_0 : 0C000000
42 rg_priority_1 : 0C000002
43 rg_priority_2 : 0C000004
44 .
45 .
46 .
47 Priority Threshold register :
48 rg_priority_threshold : 0C200000
49 Claim register :
50 rg_interrupt_id : 0C200004
51 */
52
53
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;
59 endinterface
60
61 //(*conflict_free = "rl_prioritise, prog_reg"*)
62 module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins))
63 provisos(
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)
76 );
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);
82
83 //(* noinline *)
84
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);
87 Bit#(8) outp = 0;
88 if(alu_free) begin
89 if(inp[0]==1)
90 outp[0] = 1'b1;
91 else if(inp[1]==1)
92 outp[1] = 1'b1;
93 else if(inp[2]==1)
94 outp[2] = 1'b1;
95 else if(inp[3]==1)
96 outp[3] = 1'b1;
97 else if(inp[4]==1)
98 outp[4] = 1'b1;
99 else if(inp[5]==1)
100 outp[5] = 1'b1;
101 else if(inp[6]==1)
102 outp[6] = 1'b1;
103 else if(inp[7]==1)
104 outp[7] = 1'b1;
105 end
106
107 return outp;
108 endfunction
109
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];
112 endfunction
113
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
119 if(inp[i]==1)
120 outp = fromInteger(i);
121 end
122 return {outp_valid,outp};
123 endfunction
124
125 function Reg#(t) readOnlyReg(t r);
126 return (interface Reg;
127 method t _read = r;
128 method Action _write(t x) = noAction;
129 endinterface);
130 endfunction
131
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;
135 //request to root
136 Bit#(8) root_reqs;
137
138 //grant from root
139 Bit#(8) root_grants;
140
141 for(Integer i=0;i<8;i=i+1)
142 root_reqs[i] = any_req(inp[8*fromInteger(i)+7:8*fromInteger(i)]);
143
144 root_grants = priority_encoder(root_reqs, True);
145
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]));
149 return outp;
150 endfunction
151
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)
155 if(i==28 || i == 29)
156 rg_ie[i] = readOnlyReg(True);
157 else
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)
161 if(i==28 || i == 29)
162 rg_priority_low[i] = readOnlyReg(32'h00000001);
163 else
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);
173
174 rule rl_prioritise;
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)
181 begin
182
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
187 end
188 end
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;
194 end
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)
200 begin
201
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);
206 end
207 end
208 endrule
209
210 Vector#(no_of_ir_pins, Ifc_global_interrupt) temp_ifc_irq;
211
212 for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin
213
214 temp_ifc_irq[i] = interface Ifc_global_interrupt
215
216 method Action irq_frm_gateway(Bool ir);
217 `ifdef verbose $display("Interrupt id %d is pending", i);`endif
218 rg_ip[i][0] <= True;
219 endmethod
220
221 endinterface;
222 end
223
224 interface ifc_external_irq = temp_ifc_irq;
225
226 interface ifc_prog_reg = interface Ifc_program_registers;
227
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]);
241 end
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];
246 else
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;
252 end
253 end
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]);
261 end
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]);
268 end
269 end
270 end
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
279 end
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]);
286 end
287 end
288 end
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);
293 end
294 else if(mem_req.ld_st == Store)
295 rg_priority_threshold <= mem_req.write_data[v_msb_priority:0];
296 end
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
303 end
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
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) 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
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);
373 endrule
374
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;
379
380 endmodule
381 endpackage