add core
[shakti-core.git] / src / core / core.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 core;
15
16 /* ======== Package imports ======= */
17 import Vector :: *;
18 import FIFO :: *;
19 import ConfigReg ::*;
20 import Connectable :: *;
21 /*================================== */
22
23 /*========= Project imports ======== */
24 `include "defined_parameters.bsv"
25 import defined_types ::*;
26 import Semi_FIFOF ::*;
27 import AXI4_Types :: *;
28 import AXI4_Fabric :: *;
29 import riscv :: *;
30 import imem ::*;
31 import dmem ::*;
32 import GetPut ::*;
33 import PTWalk ::*;
34 /*================================== */
35
36
37 interface Ifc_external_interrupt;
38 method Action enqueueInterrupts;
39 endinterface
40
41 interface Ifc_core_AXI4;
42 interface AXI4_Master_IFC#(`PADDR, `Reg_width, `USERSPACE) imem_master;
43 interface AXI4_Master_IFC#(`PADDR, `Reg_width, `USERSPACE) dmem_master;
44 method Action set_external_interrupt(Tuple2#(Bool,Bool) i);
45 method Action boot_sequence(Bit#(1) bootseq);
46 /* =========================== Debug Interface ===================== */
47 `ifdef Debug
48 method Action reset;
49 method Action run_continue; // Execute all instructions until the end of instruction stream
50 method Bool reset_complete;
51 method Action stop; // Stop CPU
52 method Bool halted ();
53 method Bit#(`Reg_width) read_igpr (Bit#(5) r); // Read a General-Purpose Register
54 method Action write_igpr (Bit#(5) r, Bit#(`Reg_width) d); // Write into a General-Purpose Register
55 `ifdef spfpu
56 method Bit#(`Reg_width) read_fgpr (Bit#(5) r); // Read a General-Purpose Register
57 method Action write_fgpr (Bit#(5) r, Bit#(`Reg_width) d); // Write into a General-Purpose Register
58 `endif
59 method ActionValue#(Bit#(`Reg_width)) rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data); // Read a General-Purpose Register
60 `endif
61 `ifdef CLINT
62 method Action clint_msip(Bit#(1) intrpt);
63 method Action clint_mtip(Bit#(1) intrpt);
64 method Action clint_mtime(Bit#(`Reg_width) c_mtime);
65 `endif
66 /*-========================================================================== */
67 endinterface
68
69 typedef enum {Handling_Dcache,Handling_Icache,Idle,Handling_Uncacheable} Controller_State deriving (Bits, Eq, FShow);
70
71 //(*mutually_exclusive="mkConnectionGetPut_7,mkConnectionGetPut_8")
72 `ifdef MMU (*preempts="dtlb_to_ptw,itlb_to_ptw"*) `endif
73 //`ifdef MMU (*preempts="mkConnectionGetPut_4,mkConnectionGetPut_3"*) `endif
74 (*synthesize*)
75 module mkcore_AXI4#(Bit#(`VADDR) reset_vector)(Ifc_core_AXI4);
76 Ifc_riscv riscv <-mkriscv(reset_vector);
77 AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) imem_xactor <- mkAXI4_Master_Xactor;
78 AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) dmem_xactor <- mkAXI4_Master_Xactor;
79 Ifc_imem imem <-mkimem();
80 Ifc_dmem dmem <- mkdmem;
81 Ifc_PTWalk#(`ADDR, `VADDR, 56, `PADDR, `ASID, `OFFSET) ptw <- mkPTWalk;
82 Wire#(Bit#(`Reg_width)) wr_pte <- mkWire();
83 Reg#(Bool) rg_serve_dTLB <- mkReg(False);
84
85 mkConnection(riscv.request_to_imem,imem.request_from_core);
86 mkConnection(imem.instruction_response_to_core,riscv.instruction_response_from_imem);
87 mkConnection(riscv.request_to_dmem, dmem.request_from_cpu);
88 mkConnection(dmem.response_to_cpu, riscv.response_from_dmem);
89 `ifdef MMU
90 rule itlb_to_ptw;
91 let x <- imem.to_PTW.get;
92 ptw.frm_TLB.put(x);
93 rg_serve_dTLB <=False;
94 endrule
95 rule dtlb_to_ptw;
96 let x <- dmem.to_PTW.get;
97 ptw.frm_TLB.put(x);
98 rg_serve_dTLB <=True;
99 endrule
100 rule ptw_to_itlb(!rg_serve_dTLB);
101 let x <- ptw.to_TLB.get;
102 imem.refill_TLB.put(x);
103 endrule
104 rule ptw_to_dtlb(rg_serve_dTLB);
105 let x <- ptw.to_TLB.get;
106 dmem.refill_TLB.put(x);
107 endrule
108 //mkConnection(imem.to_PTW, ptw.frm_TLB);
109 //mkConnection(dmem.to_PTW, ptw.frm_TLB);
110 //mkConnection(ptw.to_TLB, imem.refill_TLB);
111 //mkConnection(ptw.to_TLB, dmem.refill_TLB);
112 `endif
113 mkConnection(imem.prediction_response,riscv.prediction_response);
114 mkConnection(riscv.send_prediction_request,imem.send_prediction_request);
115 rule connect_training;
116 imem.training(riscv.training_data);
117 endrule
118 // (*conflict_free="connect_flush_to_imem,connect_flush_to_dmem"*)
119 // rule connect_flush_to_imem;
120 // Translation_type page_type = Execution;
121 // if(riscv.flush_imem!=None) begin
122 // ptw.flush(page_type);
123 // end
124 // endrule
125 rule connect_flush_to_dmem;
126 Translation_type page_type = Load;
127 if(riscv.flush_dmem)
128 dmem.flush();
129 // if(riscv.flush_dmem) begin
130 // ptw.flush(page_type);
131 // end
132 endrule
133
134 `ifdef MMU
135 //rule fence_iTLB;
136 // `ifdef verbose $display($time ,"\tCORE: iTLB is being flushed"); `endif
137 // imem.fence_itlb(dmem.fence_itlb);
138 //endrule
139 rule send_permissions_to_tlb;
140 ptw.satp_frm_csr(riscv.send_satp);
141 imem.translation_protection_frm_csr(riscv.mmu_cache_disable[0],
142 riscv.perm_to_TLB,
143 riscv.send_satp[`Reg_width-1:`Reg_width-`ASID-4]);
144 dmem.translation_protection_frm_csr(riscv.mmu_cache_disable[0],
145 riscv.perm_to_TLB,
146 riscv.send_satp[`Reg_width-1:`Reg_width-`ASID-4]);
147 endrule
148 rule send_pte_pointer;
149 let x <- ptw.ifc_memory.send_PTE_pointer;
150 dmem.get_pte_pointer(x);
151 endrule
152 rule get_pte_entry;
153 let x <- dmem.send_pte;
154 wr_pte <= x;
155 endrule
156 rule send_pte_entry;
157 ptw.ifc_memory.get_PTE(wr_pte);
158 endrule
159 rule fence_tlbs;
160 dmem.fence_dtlb(riscv.fence_tlbs);
161 imem.fence_itlb(riscv.fence_tlbs);
162 endrule
163 `endif
164 rule fence_stall_icache;
165 imem.stall_fetch(dmem.stall_fetch);
166 endrule
167 Reg#(Bool) rg_update_a_bit <- mkReg(False);
168 Reg#(Bool) rg_update_b_bit <- mkReg(False);
169 Reg#(Maybe#(Bit#(TMul#(8,TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))))) rg_data_line <-mkReg(tagged Invalid);
170 Reg#(Bit#(8)) rg_burst_count<-mkReg(0);
171 Reg#(Bool) rg_wait_for_response[2]<-mkCReg(2,False);
172 rule check_read_request_to_memory_from_dcache;
173 let info<-dmem.request_to_memory_read;
174 Bit#(2) arburst=2;
175 if(info.burst_length==1)
176 arburst=1;
177 let read_request = AXI4_Rd_Addr {araddr: truncate(info.address), aruser: 0, arlen: info.burst_length-1, arsize: zeroExtend(info.transfer_size), arburst: arburst, arid:'d0}; // arburst: 00-FIXED 01-INCR 10-WRAP
178 dmem_xactor.i_rd_addr.enq(read_request);
179 `ifdef verbose $display($time,"\tCORE: Sending Read Request from DCACHE for Address: %h Burst Length: %h",info.address,info.burst_length); `endif
180 endrule
181 rule check_write_request_to_memory_from_dcache(rg_data_line matches tagged Invalid &&& !rg_wait_for_response[1]);
182 let info<-dmem.request_to_memory_write;
183 /*=== Need to shift the data apprpriately while sending write requests===== */
184 Bit#(`Reg_width) actual_data=info.data_line[`Reg_width-1:0];
185 Bit#(8) write_strobe=info.transfer_size==0?8'b1:info.transfer_size==1?8'b11:info.transfer_size==2?8'hf:8'hff;
186 if(info.transfer_size!=3)begin // 8-bit write;
187 write_strobe=write_strobe<<(info.address[`byte_offset:0]);
188 end
189 // info.address[2:0]=0; // also make the address 64-bit aligned
190 /*========================================================================= */
191 let aw = AXI4_Wr_Addr {awaddr: truncate(info.address), awuser:0, awlen: info.burst_length-1, awsize: zeroExtend(info.transfer_size), awburst: 'b01, awid:'d0}; // arburst: 00-FIXED 01-INCR 10-WRAP
192 let w = AXI4_Wr_Data {wdata: actual_data, wstrb: write_strobe, wlast:info.burst_length>1?False:True, wid:'d0};
193 dmem_xactor.i_wr_addr.enq(aw);
194 dmem_xactor.i_wr_data.enq(w);
195 `ifdef verbose $display($time,"\tCORE: Sending Write Request from DCACHE for Address: %h BurstLength: %h Data: %h WriteStrobe: %b",info.address,info.burst_length,info.data_line, write_strobe); `endif
196 if(info.burst_length>1)begin // only enable the next rule when doing a line write in burst mode.
197 rg_data_line<=tagged Valid (info.data_line>>`Reg_width);
198 rg_burst_count<=rg_burst_count+1;
199 end
200 rg_wait_for_response[1]<=True;
201 endrule
202 rule send_burst_write_data(rg_data_line matches tagged Valid .data_line);
203 /*== Since this is going to always be a line write request in burst mode No need of shifting data and address=== */
204 let w = AXI4_Wr_Data {wdata: truncate(data_line), wstrb: 8'hff , wlast:(rg_burst_count==`DCACHE_BLOCK_SIZE-1), wid:'d0};
205 dmem_xactor.i_wr_data.enq(w);
206 `ifdef verbose $display($time,"\tCORE: Sending DCACHE Write Data: %h Burst: %d",data_line,rg_burst_count); `endif
207 if(rg_burst_count==`DCACHE_BLOCK_SIZE-1)begin
208 rg_burst_count<=0;
209 rg_data_line<=tagged Invalid;
210 end
211 else begin
212 rg_data_line<=tagged Valid (data_line>>`Reg_width);
213 rg_burst_count<=rg_burst_count+1;
214 end
215 endrule
216 rule check_read_request_to_memory_from_icache;
217 let info <-imem.request_to_memory;
218 let read_request = AXI4_Rd_Addr {araddr: truncate(info.address), aruser: 0, arlen: info.burst_length-1, arsize: info.transfer_size, arburst: 'b10, arid:'d1}; // arburst: 00-FIXED 01-INCR 10-WRAP
219 imem_xactor.i_rd_addr.enq(read_request);
220 `ifdef verbose $display($time,"\tCORE: Sending Read Request from ICACHE for Address: %h Burst Length: %h",info.address,info.burst_length); `endif
221 endrule
222 rule send_read_response_from_memory_to_dcache(dmem_xactor.o_rd_data.first.rid == 'd0);
223 let response <- pop_o (dmem_xactor.o_rd_data);
224 let bus_error_from_memory = (response.rresp==AXI4_OKAY) ? 0 : 1;
225 `ifdef verbose $display($time,"\tCORE: Sending Response to DCACHE: ",fshow(response)); `endif
226 dmem.response_from_memory_read(From_Memory{data_line:response.rdata,bus_error:bus_error_from_memory,last_word:response.rlast});
227 endrule
228 rule send_read_response_from_memory_to_icache(imem_xactor.o_rd_data.first.rid == 'd1);
229 let response <- pop_o (imem_xactor.o_rd_data);
230 let bus_error_from_memory = (response.rresp==AXI4_OKAY) ? 0 : 1;
231 `ifdef verbose $display($time,"\tCORE: Sending Response to ICACHE: ",fshow(response)); `endif
232 imem.response_from_memory(From_Memory{data_line:response.rdata,bus_error:bus_error_from_memory, last_word:response.rlast});
233 endrule
234 rule send_write_response_to_dcache(rg_wait_for_response[0] && dmem_xactor.o_wr_resp.first.bid == 'd0);
235 let response<-pop_o(dmem_xactor.o_wr_resp);
236 let bus_error_from_memory = (response.bresp==AXI4_OKAY) ? 0 : 1;
237 `ifdef verbose $display($time,"\tCORE: Received Write Response:",fshow(response)); `endif
238 dmem.response_from_memory_write(From_Memory{data_line:0,bus_error:bus_error_from_memory,last_word:True});
239 rg_wait_for_response[0]<=False;
240 endrule
241
242 interface imem_master = imem_xactor.axi_side;
243 interface dmem_master = dmem_xactor.axi_side;
244 `ifdef Debug
245 method run_continue=riscv.run_continue;
246 method reset_complete=riscv.reset_complete;
247 method stop=riscv.stop;
248 method halted=riscv.halted;
249 method Bit#(`Reg_width)read_igpr(Bit#(5) r);
250 return riscv.read_debug_igpr(r);
251 endmethod
252 method Action write_igpr(Bit#(5) r, Bit#(`Reg_width)d);
253 riscv.write_debug_igpr(r,d);
254 endmethod
255 `ifdef spfpu
256 method Bit#(`Reg_width) read_fgpr(Bit#(5) r);
257 return riscv.read_debug_fgpr(r);
258 endmethod
259 method Action write_fgpr(Bit#(5) r, Bit#(`Reg_width)d);
260 riscv.write_debug_fgpr(r,d);
261 endmethod
262 `endif
263 method ActionValue#(Bit#(`Reg_width)) rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data)=riscv.rw_csr(r,write,data);
264 method Action reset=riscv.reset;
265 `endif
266 method Action boot_sequence(Bit#(1) bootseq)=riscv.boot_sequence(bootseq);
267 method Action set_external_interrupt(Tuple2#(Bool,Bool) i)=riscv.set_external_interrupt(i);
268 `ifdef CLINT
269 method Action clint_msip(Bit#(1) intrpt)=riscv.clint_msip(intrpt);
270 method Action clint_mtip(Bit#(1) intrpt)=riscv.clint_mtip(intrpt);
271 method Action clint_mtime(Bit#(`Reg_width) c_mtime)=riscv.clint_mtime(c_mtime);
272 `endif
273 endmodule
274 endpackage