add core
[shakti-core.git] / src / core / riscv.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 Author Names : Neel Gala
15 Email ID : neelgala@gmail.com
16
17 Description :
18 This is the 64-bit core of the c_class processor. It containes rules for each stage. The description of each stage
19 is given in the respective rules.
20 */
21 package riscv;
22
23 /*===== Package imports === */
24 import SpecialFIFOs::*;
25 import FIFO::*;
26 import FIFOF::*;
27 import DReg::*;
28 import Vector ::*;
29 import TxRx::*;
30 import Connectable::*;
31 import GetPut::*;
32 /*========================= */
33
34 /*=== Project imports -===== */
35 import fetch_stage::*;
36 import decode_opfetch::*;
37 import execute_stage::*;
38 import memory_stage::*;
39 import csr::*;
40 `include "defined_parameters.bsv"
41 import defined_types::*;
42 /*========================= */
43
44 interface Ifc_riscv;
45 interface Get#(Tuple5#(Bit#(2),Bit#(`VADDR),Bit#(`VADDR),Bool,Bit#(3))) request_to_imem;
46 method Action instruction_response_from_imem(Maybe#(Tuple7#(Bit#(`VADDR),Bit#(2),Bit#(`VADDR),Bit#(32), Trap_type, Bit#(`PERFMONITORS),Bit#(3))) x);
47 interface Put#(Tuple4#(Bit#(3),Bit#(`VADDR),Bit#(`VADDR),Bit#(2))) prediction_response;
48 interface Get#(Tuple2#(Bit#(3),Bit#(`VADDR))) send_prediction_request;
49 method Maybe#(Training_data#(`VADDR)) training_data;
50 interface Get#(Tuple2#(Memout,Bit#(1))) request_to_dmem;
51 interface Put#(Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type, Bit#(`PERFMONITORS),Bit#(1)))) response_from_dmem;
52 method Bool flush_dmem;
53 method Action set_external_interrupt(Tuple2#(Bool,Bool) i);
54 `ifdef MMU
55 method Bit#(`Reg_width) send_satp;
56 method Chmod perm_to_TLB;
57 method Bit#(`Reg_width) mmu_cache_disable;
58 method Fence_VMA_type#(`VADDR) fence_tlbs;
59 `endif
60 (*always_ready,always_enabled*)
61 method Action boot_sequence(Bit#(1) bootseq);
62 /* =========================== Debug Interface ===================== */
63 `ifdef Debug
64 method Bit#(`Reg_width) read_debug_igpr (Bit#(5) r); // Read a General-Purpose Register
65 method Action write_debug_igpr (Bit#(5) r, Bit#(`Reg_width) d); // Write a General-Purpose Register
66 method Bit#(`Reg_width) read_debug_fgpr (Bit#(5) r); // Read a General-Purpose Register
67 method Action write_debug_fgpr (Bit#(5) r, Bit#(`Reg_width) d); // Write a General-Purpose Register
68 method Action reset;
69 method Action run_continue; // Execute all instructions until the end of instruction stream
70 method Bool reset_complete;
71 method Action stop; // Stop CPU
72 method Bool halted ();
73 method ActionValue#(Bit#(`Reg_width)) rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data); // Read a General-Purpose Register
74 `endif
75 `ifdef CLINT
76 method Action clint_msip(Bit#(1) intrpt);
77 method Action clint_mtip(Bit#(1) intrpt);
78 method Action clint_mtime(Bit#(`Reg_width) c_mtime);
79 `endif
80 /*-========================================================================== */
81 endinterface
82
83 (*synthesize*)
84 (*conflict_free="get_trap_data_from_csr,rl_write_back"*)
85 module mkriscv#(Bit#(`VADDR) reset_vector)(Ifc_riscv);
86
87 function Bool checkloadtrigger(TriggerData tdata, Bit#(`Reg_width) lsdata);
88 if(tdata.ttype matches tagged Data .data)
89 if(tdata.matchscheme==0 && data==lsdata)
90 return True;
91 else if(tdata.matchscheme==2 && data>=lsdata)
92 return True;
93 else if(tdata.matchscheme==3 && data<=lsdata)
94 return True;
95 else if(tdata.matchscheme==4 && data[31:0]==(data[63:32]&lsdata[31:0]))
96 return True;
97 else if(tdata.matchscheme==5 && data[31:0]==(data[63:32]&lsdata[63:32]))
98 return True;
99 else
100 return False;
101 else
102 return False;
103 endfunction
104
105 /* =================== PIPELINE FIFOS ======================================================================== */
106 FIFOF#(IF_ID_type) ff_if_id <-mkSizedFIFOF(2); // instantiating ISB between fetch and decode
107 FIFOF#(ID_IE_type) ff_id_ie <-mkSizedFIFOF(2); // instantiating ISB between decode and exec
108 FIFOF#(IE_IMEM_type) ff_ie_imem <-mkSizedFIFOF(2); // instantiating ISB between exec and memory
109 FIFOF#(IMEM_IWB_type) ff_imem_iwb <-mkLFIFOF(); // instantiating ISB between memory and write-back
110 Wire#(Maybe#(Operand_forwading_type)) wr_forward_from_WBS <-mkDWire(tagged Invalid);// holds the forwarded data from the memory stage
111 Wire#(Maybe#(Tuple3#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS)))) wr_response_to_cpu <- mkDWire(tagged Invalid);
112 /*============================================================================================================*/
113
114 /* ============================================ Flushing related regs/wires=================================== */
115 Reg#(Bool) wb_stage_flush <-mkDWire(False); // if true inidicates that the entire pipe needs to be flushed
116 Reg#(Bool) dmem_flush <-mkDWire(False); // if true inidicates that the entire pipe needs to be flushed
117 Reg#(Bit#(`VADDR)) wr_effective_address1 <-mkDWire(0); // captures the new pc when an trap is taken.// captures the new pc when an trap is taken.
118 Wire#(Bool) wr_change_wEpoch<-mkDWire(False);
119 Wire#(Fence_VMA_type#(`VADDR)) wr_sfence <- mkWire();
120 Wire#(Bit#(`PERFMONITORS)) wr_dcache_perfmon <- mkDWire(0);
121 Reg#(Bit#(1)) wEpoch <-mkReg(0);
122 /*============================================================================================================*/
123
124 /*========================================== Debug related registers/wires ================================== */
125 Reg #(Bool) rg_stop_requested[2] <- mkCReg(2, False); // True if a stop was requested by the previous instruction
126 Reg #(Bool) rg_resume_requested[2] <- mkCReg(2, False); // True if a stop was requested by the previous instruction
127 Reg #(Bool) rg_reset_requested[2] <- mkCReg(2, False); // True if a stop was requested by the previous instruction
128 /*============================================================================================================*/
129
130 /* ================= Instantiating all the modules required in the pipe =================================== */
131 Ifc_fetch fetch <-mkfetch(reset_vector);
132 Ifc_decode_opfetch decode <-mkdecode_opfetch;
133 Ifc_execute_stage execute_stage <-mkexecute_stage;
134 Ifc_memory_stage memory_stage <-mkmemory_stage;
135 Ifc_csr csr <-mkcsr();
136 /*============================================================================================================*/
137
138 /* ================== flushing the core partially or completely =================================================== */
139 let {flush_from_execute,effective_address}=execute_stage.generate_flush; // capture the flush generated by the decode stage.
140
141 /* this rule flushes the insruction fetch stage since the decode stage has generated a branch misprediction.
142 The flush can also be generated is the instruction in the decode stage is a Fence.I operation. This difference
143 in the misprediction and fence is captured in flush_from_decode wire.*/
144 rule rl_flush_first_two_stages(flush_from_execute!=None && !wb_stage_flush);
145 `ifdef verbose $display($time,"\tFlushing the fetch and Decode stage alone"); `endif
146 fetch.flush(effective_address,flush_from_execute);
147 endrule
148
149 /*=== These rules are fired when an exception or interrupt or ECALL has been generated/taken at the write-back stage===*/
150 rule rl_flush_fetch(wb_stage_flush);
151 `ifdef verbose $display($time,"\tFLUSH FIRING TO ALL STAGES"); `endif
152 fetch.flush(wr_effective_address1,AccessFlush);
153 execute_stage.flush_prf;
154 endrule
155 rule rl_flush_decode_stage(wb_stage_flush||flush_from_execute!=None);
156 decode.flush();
157 endrule
158 rule rl_change_eEpoch(flush_from_execute!=None && !wr_change_wEpoch);
159 fetch.update_eEpoch;
160 decode.update_eEpoch;
161 endrule
162 rule ras_push_connect;
163 fetch.push_ras(execute_stage.ras_push);
164 endrule
165 rule rl_change_wEpoch(wr_change_wEpoch);
166 fetch.update_wEpoch;
167 decode.update_wEpoch;
168 memory_stage.update_wEpoch;
169 execute_stage.update_wEpoch;
170 endrule
171 /*=============================================================================================================*/
172
173 /*============= Make PIPE Connections =========== */
174 mkConnection(fetch.tx_out,ff_if_id);
175 mkConnection(ff_if_id,decode.rx_in);
176
177 mkConnection(decode.tx_out,ff_id_ie);
178 mkConnection(ff_id_ie,execute_stage.rx_in);
179
180 mkConnection(execute_stage.tx_out,ff_ie_imem);
181 mkConnection(ff_ie_imem,memory_stage.rx_in);
182
183 RX#(IMEM_IWB_type) rx <-mkRX();
184 mkConnection(memory_stage.tx_out, ff_imem_iwb);
185 mkConnection(ff_imem_iwb,rx.e);
186 /*===================================================== */
187 /* This rule connects the forwarding data from the memory and execution
188 stages to the operand fetch stage */
189 rule connect_forwarding_data1;
190 execute_stage._forwarding_from_memory(memory_stage.forwarding_data); // forwarding from memory unit.
191 endrule
192 rule send_misa_to_decode;
193 decode.misa(csr.misa);
194 endrule
195 rule get_trap_data_from_csr(ff_if_id.notEmpty);
196 let {y,x}<-csr.check_for_trap(`ifdef Debug rg_stop_requested[1],rg_resume_requested[1],rg_reset_requested[1], `endif ff_if_id.first.program_counter,ff_if_id.first.instruction);
197 decode.trap_from_csr(tuple2(y,x));
198 endrule
199 `ifdef Debug
200 rule disable_debug_requests;
201 if(csr.halted && rg_stop_requested[1])
202 rg_stop_requested[1]<=False;
203 if(!csr.halted && rg_resume_requested[1])
204 rg_resume_requested[1]<=False;
205 if(csr.reset_mode && rg_reset_requested[1])
206 rg_reset_requested[1]<=False;
207 endrule
208 `endif
209 /* This rule is used to transfer the updated value
210 of the FCSR register to the floating point units */
211 rule get_data_from_csr;
212 execute_stage.roundingmode(csr.roundingmode);
213 endrule
214 `ifdef Debug
215 rule connect_trigger_info_memorystage;
216 memory_stage.storetrigger_info(csr.store_triggerdata);
217 memory_stage.loadtrigger_info(csr.load_triggerdata);
218 endrule
219 `endif
220
221 rule connect_mxl;
222 execute_stage.inferred_xlen(csr.inferred_xlen);
223 decode.inferred_xlen(csr.inferred_xlen);
224 endrule
225
226 /* ==================================================================================================================================*/
227
228
229 /* Modularizing this stage is too cumbersome since it will encapsulate the debug registers and the CSR
230 which communicate with the rest of the pipe in adhoc fashion. */
231 rule rl_write_back;
232 WriteBackType info=rx.u.first().commit_data;
233 Bool start_write=True;
234 Bit#(`VADDR) memaddress=0;
235 if(info matches tagged RESULT .arith_data)
236 memaddress=truncate(arith_data.aluresult);
237 let exception=rx.u.first.exception;
238 Bit#(`PERFMONITORS) pm=rx.u.first.perfmonitors;
239 /*========================================================= */
240 `ifdef verbose $display($time,"\t*****************WRITE BACK STAGE*************************\t PC: %h PID: %d PERF: %h Instr-Epochs: %b Epochs: %b",rx.u.first.program_counter,rx.u.first.pid,pm,rx.u.first.epochs,wEpoch); `endif
241 rx.u.deq(); // release the previous FIFO
242 Bit#(3) debugcause=rx.u.first.debugcause;
243 `ifdef Debug
244 if(csr.step_now)begin
245 exception=tagged Interrupt DebugInterrupt;
246 debugcause=4;
247 end
248 `endif
249 if(rx.u.first.epochs[0]!=wEpoch)begin
250 `ifdef verbose $display($time,"\tWRITEBACK: Dropping instruction"); `endif
251 end
252 else if(exception matches tagged None)begin
253 `ifdef MMU
254 if(info matches tagged SYSTEM .priv) begin
255 if(priv.csr_address[11:5]=='b0001001)
256 wr_sfence <= Fence_VMA_type{rs1:truncate(priv.rs1),rs2:truncate(priv.rs2)};
257 end
258 `endif
259 let {flush,ea,destination_value,commit}<-csr.system_instruction(info,rx.u.first.program_counter,pm `ifdef simulate ,rx.u.first.instruction,rx.u.first.rd_type,rx.u.first.destination `endif );
260 if(commit)begin
261 `ifdef verbose $display($time,"\tWRITEBACK: Writing into register: %d with value: %h",rx.u.first.destination,destination_value); `endif
262 decode.write_rd(rx.u.first.destination,destination_value,rx.u.first.rd_type);
263 end
264 wb_stage_flush<=flush;
265 if(info matches tagged SYSTEM .x)
266 dmem_flush<=True;
267
268 if(flush) begin
269 wEpoch<=~wEpoch;
270 wr_change_wEpoch<=True;
271 end
272 wr_effective_address1<=ea;
273 `ifdef verbose $display($time,"\tWRITEBACK: Flush: ",fshow(flush)," EA: %h",ea); `endif
274 end
275 else begin
276 let {ea,flush}<-csr.take_trap(exception,debugcause,rx.u.first.program_counter,truncate(memaddress));
277 `ifdef verbose $display($time,"\tWRITEBACK: Taking trap ea: %h",ea); `endif
278 if(flush) begin
279 wEpoch<=~wEpoch;
280 wr_change_wEpoch<=True;
281 end
282 if(exception matches tagged Interrupt .in &&& flush)
283 dmem_flush<=True;
284 if(exception matches tagged Exception .cause)begin
285 let ex=pack(cause);
286 if(ex!=4 && ex!=5 && ex!=6 && ex!=7 && ex!=13 && ex!=15)
287 dmem_flush<=True;
288 end
289 wb_stage_flush<=flush;
290 wr_effective_address1<=ea;
291 end
292 endrule
293 /*====================================== END OF PIPE STAGES ============================================= */
294 //////////////////////////// definition of methods /////////////////////////////////////////////////////////////////////////////////
295 interface request_to_imem=fetch.request_to_imem;
296 method Action instruction_response_from_imem(Maybe#(Tuple7#(Bit#(`VADDR),Bit#(2),Bit#(`VADDR),Bit#(32), Trap_type, Bit#(`PERFMONITORS),Bit#(3))) x)=fetch.instruction_response_from_imem(x);
297 interface prediction_response =fetch.prediction_response;
298 interface send_prediction_request=fetch.send_prediction_request;
299 method training_data=execute_stage.training_data;
300 interface request_to_dmem = execute_stage.to_dmem;
301 interface response_from_dmem = memory_stage.response_from_dmem;
302 method Bool flush_dmem;
303 return dmem_flush;
304 endmethod
305 method Action set_external_interrupt(Tuple2#(Bool,Bool) i) = csr.set_external_interrupt(i);
306
307 `ifdef MMU
308 method Bit#(`Reg_width) send_satp = csr.send_satp;
309 method Chmod perm_to_TLB = csr.perm_to_TLB;
310 method Bit#(`Reg_width) mmu_cache_disable = csr.mmu_cache_disable;
311 method Fence_VMA_type#(`VADDR) fence_tlbs;
312 return wr_sfence;
313 endmethod
314
315 `endif
316
317 //interface ifc_riscv_interrupt_pins = memory_stage.plic_ifc_external_irq;
318 //method Bit#(TLog#(`INTERRUPT_PINS)) intrpt_completion;
319 // return memory_stage.plic_intrpt_completion;
320 //endmethod
321 /* ================================== Debug related methods ======================= */
322 `ifdef Debug
323 method Action reset;
324 `ifdef verbose $display($time,"\tsetting the reset request"); `endif
325 rg_reset_requested[0]<=True;
326 endmethod
327 method Action run_continue();
328 `ifdef verbose $display($time,"\tsetting the resume reqiest to True"); `endif
329 rg_resume_requested[0]<=True;
330 endmethod
331 method Bool reset_complete;
332 return !csr.reset_mode ;
333 endmethod
334 method Action stop;
335 `ifdef verbose $display($time,"RISCV: REQUESTING HALT"); `endif
336 rg_stop_requested[0]<=True;
337 endmethod
338 method Bool halted ();
339 return csr.halted;
340 endmethod
341 method read_debug_igpr (Bit#(5) r) = decode.read_debug_igpr(r); // Read a General-Purpose Register
342 method Action write_debug_igpr (Bit#(5) r, Bit#(`Reg_width) d)=decode.write_debug_igpr(r,d); // Write a General-Purpose Register
343 method read_debug_fgpr (Bit#(5) r)=decode.read_debug_fgpr(r); // Read a General-Purpose Register
344 method Action write_debug_fgpr (Bit#(5) r, Bit#(`Reg_width) d)=decode.write_debug_fgpr(r,d); // Write a General-Purpose Register
345 method ActionValue#(Bit#(`Reg_width)) rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data) =csr.rw_debug_csr(r,write,data); // TODO
346 `endif
347 `ifdef CLINT
348 method Action clint_msip(Bit#(1) intrpt)=csr.clint_msip(intrpt);
349 method Action clint_mtip(Bit#(1) intrpt)=csr.clint_mtip(intrpt);
350 method Action clint_mtime(Bit#(`Reg_width) c_mtime)=csr.clint_mtime(c_mtime);
351 `endif
352 /* ==================================================================================== */
353 method Action boot_sequence(Bit#(1) bootseq)=csr.boot_sequence(bootseq);
354 endmodule
355 endpackage
356
357