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 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
14 Author Names : Neel Gala
15 Email ID : neelgala@gmail.com
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.
23 /*===== Package imports === */
24 import SpecialFIFOs::*;
30 import Connectable::*;
32 /*========================= */
34 /*=== Project imports -===== */
35 import fetch_stage::*;
36 import decode_opfetch::*;
37 import execute_stage::*;
38 import memory_stage::*;
40 `include "core_parameters.bsv"
41 import defined_types::*;
42 /*========================= */
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);
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;
60 (*always_ready,always_enabled*)
61 method Action boot_sequence(Bit#(1) bootseq);
62 /* =========================== Debug Interface ===================== */
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
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
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);
80 /*-========================================================================== */
84 (*conflict_free="get_trap_data_from_csr,rl_write_back"*)
85 module mkriscv#(Bit#(`VADDR) reset_vector)(Ifc_riscv);
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)
91 else if(tdata.matchscheme==2 && data>=lsdata)
93 else if(tdata.matchscheme==3 && data<=lsdata)
95 else if(tdata.matchscheme==4 && data[31:0]==(data[63:32]&lsdata[31:0]))
97 else if(tdata.matchscheme==5 && data[31:0]==(data[63:32]&lsdata[63:32]))
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 /*============================================================================================================*/
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 /*============================================================================================================*/
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 /*============================================================================================================*/
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 /*============================================================================================================*/
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.
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);
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;
155 rule rl_flush_decode_stage(wb_stage_flush||flush_from_execute!=None);
158 rule rl_change_eEpoch(flush_from_execute!=None && !wr_change_wEpoch);
160 decode.update_eEpoch;
162 rule ras_push_connect;
163 fetch.push_ras(execute_stage.ras_push);
165 rule rl_change_wEpoch(wr_change_wEpoch);
167 decode.update_wEpoch;
168 memory_stage.update_wEpoch;
169 execute_stage.update_wEpoch;
171 /*=============================================================================================================*/
173 /*============= Make PIPE Connections =========== */
174 mkConnection(fetch.tx_out,ff_if_id);
175 mkConnection(ff_if_id,decode.rx_in);
177 mkConnection(decode.tx_out,ff_id_ie);
178 mkConnection(ff_id_ie,execute_stage.rx_in);
180 mkConnection(execute_stage.tx_out,ff_ie_imem);
181 mkConnection(ff_ie_imem,memory_stage.rx_in);
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.
192 rule send_misa_to_decode;
193 decode.misa(csr.misa);
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));
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;
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);
215 rule connect_trigger_info_memorystage;
216 memory_stage.storetrigger_info(csr.store_triggerdata);
217 memory_stage.loadtrigger_info(csr.load_triggerdata);
222 execute_stage.inferred_xlen(csr.inferred_xlen);
223 decode.inferred_xlen(csr.inferred_xlen);
226 /* ==================================================================================================================================*/
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. */
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;
244 if(csr.step_now)begin
245 exception=tagged Interrupt DebugInterrupt;
249 if(rx.u.first.epochs[0]!=wEpoch)begin
250 `ifdef verbose $display($time,"\tWRITEBACK: Dropping instruction"); `endif
252 else if(exception matches tagged None)begin
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)};
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 );
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);
264 wb_stage_flush<=flush;
265 if(info matches tagged SYSTEM .x)
270 wr_change_wEpoch<=True;
272 wr_effective_address1<=ea;
273 `ifdef verbose $display($time,"\tWRITEBACK: Flush: ",fshow(flush)," EA: %h",ea); `endif
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
280 wr_change_wEpoch<=True;
282 if(exception matches tagged Interrupt .in &&& flush)
284 if(exception matches tagged Exception .cause)begin
286 if(ex!=4 && ex!=5 && ex!=6 && ex!=7 && ex!=13 && ex!=15)
289 wb_stage_flush<=flush;
290 wr_effective_address1<=ea;
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;
305 method Action set_external_interrupt(Tuple2#(Bool,Bool) i) = csr.set_external_interrupt(i);
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;
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;
321 /* ================================== Debug related methods ======================= */
324 `ifdef verbose $display($time,"\tsetting the reset request"); `endif
325 rg_reset_requested[0]<=True;
327 method Action run_continue();
328 `ifdef verbose $display($time,"\tsetting the resume reqiest to True"); `endif
329 rg_resume_requested[0]<=True;
331 method Bool reset_complete;
332 return !csr.reset_mode ;
335 `ifdef verbose $display($time,"RISCV: REQUESTING HALT"); `endif
336 rg_stop_requested[0]<=True;
338 method Bool halted ();
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
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);
352 /* ==================================================================================== */
353 method Action boot_sequence(Bit#(1) bootseq)=csr.boot_sequence(bootseq);