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 /* ======== Package imports ======= */
20 import Connectable :: *;
21 /*================================== */
23 /*========= Project imports ======== */
24 `include "defined_parameters.bsv"
25 import defined_types ::*;
26 import Semi_FIFOF ::*;
27 import AXI4_Types :: *;
28 import AXI4_Fabric :: *;
34 /*================================== */
37 interface Ifc_external_interrupt;
38 method Action enqueueInterrupts;
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 ===================== */
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
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
59 method ActionValue#(Bit#(`Reg_width)) rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data); // Read a General-Purpose Register
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);
66 /*-========================================================================== */
69 typedef enum {Handling_Dcache,Handling_Icache,Idle,Handling_Uncacheable} Controller_State deriving (Bits, Eq, FShow);
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
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);
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);
91 let x <- imem.to_PTW.get;
93 rg_serve_dTLB <=False;
96 let x <- dmem.to_PTW.get;
100 rule ptw_to_itlb(!rg_serve_dTLB);
101 let x <- ptw.to_TLB.get;
102 imem.refill_TLB.put(x);
104 rule ptw_to_dtlb(rg_serve_dTLB);
105 let x <- ptw.to_TLB.get;
106 dmem.refill_TLB.put(x);
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);
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);
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);
125 rule connect_flush_to_dmem;
126 Translation_type page_type = Load;
129 // if(riscv.flush_dmem) begin
130 // ptw.flush(page_type);
136 // `ifdef verbose $display($time ,"\tCORE: iTLB is being flushed"); `endif
137 // imem.fence_itlb(dmem.fence_itlb);
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],
143 riscv.send_satp[`Reg_width-1:`Reg_width-`ASID-4]);
144 dmem.translation_protection_frm_csr(riscv.mmu_cache_disable[0],
146 riscv.send_satp[`Reg_width-1:`Reg_width-`ASID-4]);
148 rule send_pte_pointer;
149 let x <- ptw.ifc_memory.send_PTE_pointer;
150 dmem.get_pte_pointer(x);
153 let x <- dmem.send_pte;
157 ptw.ifc_memory.get_PTE(wr_pte);
160 dmem.fence_dtlb(riscv.fence_tlbs);
161 imem.fence_itlb(riscv.fence_tlbs);
164 rule fence_stall_icache;
165 imem.stall_fetch(dmem.stall_fetch);
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;
175 if(info.burst_length==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
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]);
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;
200 rg_wait_for_response[1]<=True;
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
209 rg_data_line<=tagged Invalid;
212 rg_data_line<=tagged Valid (data_line>>`Reg_width);
213 rg_burst_count<=rg_burst_count+1;
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
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});
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});
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;
242 interface imem_master = imem_xactor.axi_side;
243 interface dmem_master = dmem_xactor.axi_side;
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);
252 method Action write_igpr(Bit#(5) r, Bit#(`Reg_width)d);
253 riscv.write_debug_igpr(r,d);
256 method Bit#(`Reg_width) read_fgpr(Bit#(5) r);
257 return riscv.read_debug_fgpr(r);
259 method Action write_fgpr(Bit#(5) r, Bit#(`Reg_width)d);
260 riscv.write_debug_fgpr(r,d);
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;
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);
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);