add ClintBase
[shakti-core.git] / src / core / dmem.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 dmem;
15
16 import defined_types :: *;
17 import dTLB :: *;
18 import dcache_asic :: *;
19 import GetPut :: *;
20 import ConfigReg :: *;
21 import FIFOF :: *;
22 import SpecialFIFOs :: *;
23 import MemoryMap :: *;
24 import DReg::*;
25 import ConfigReg::*;
26 `include "core_parameters.bsv"
27
28 interface Ifc_dmem;
29 /*======= Mandatory Interface to the core ================ */
30 interface Put#(Tuple2#(Memout,Bit#(1))) request_from_cpu;
31 interface Get#(Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type, Bit#(`PERFMONITORS),Bit#(1)))) response_to_cpu;
32 method Action flush( );
33 // method Bool reset_complete;
34 method Bool stall_fetch;
35 /*=============================================== */
36 /*======= Mandatory Interface to the external bus ================ */
37 method ActionValue#(To_Memory#(`PADDR)) request_to_memory_read;
38 method ActionValue#(To_Memory_Write) request_to_memory_write;
39 method Action response_from_memory_read(From_Memory#(`DCACHE_WORD_SIZE) resp);
40 method Action response_from_memory_write(From_Memory#(`DCACHE_WORD_SIZE) resp);
41 /*=============================================== */
42 /*======= Interface to the DTLB ================ */
43 `ifdef MMU
44 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
45 interface Get#(Request_PPN_PTW#(`VADDR,`OFFSET)) to_PTW;
46 interface Put#(Tuple2#(Bool,To_TLB#(`PADDR,`OFFSET,`ASID))) refill_TLB;
47 method Action get_pte_pointer(Request_PTE_memory#(`Reg_width) pte);
48 method Action fence_dtlb(Fence_VMA_type#(`VADDR) rsdata);
49 method ActionValue#(Bit#(`Reg_width)) send_pte;
50 //method Action fence_TLB(Fence_VMA_type#(`ADDR) rsdata);
51 `endif
52 /*=============================================== */
53 endinterface
54 //(*conflict_free="request_from_cpu_put, response_to_cpu_get"*)
55 (*synthesize*)
56 module mkdmem(Ifc_dmem);
57 Ifc_dcache dcache <- mkdcache;
58 `ifdef MMU
59 Ifc_dTLB dtlb <- mkdTLB;
60 Reg#(Maybe#(Tuple2#(Memout,Bit#(1)))) rg_dtlb_metadata[2] <- mkCReg(2,tagged Invalid);
61 `endif
62 ConfigReg#(Bool) rg_serve_ptw <- mkConfigReg(False);
63 Reg#(Maybe#(Request_PTE_memory#(`Reg_width))) rg_pte_pointer[2] <- mkCReg(2,tagged Invalid);
64 FIFOF#(Maybe#(Tuple2#(Bit#(`Reg_width), Maybe#(Exception_cause)))) ff_response_to_cpu <- mkSizedBypassFIFOF(1);
65 Wire#(From_Memory#(`DCACHE_WORD_SIZE)) wr_read_response_from_memory <- mkWire();
66 Reg#(Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS),Bit#(1)))) wr_response_to_cpu[3] <-mkCReg(3,tagged Invalid);
67 Reg#(Bit#(1)) epochs[2] <-mkCReg(2,0);
68 Reg#(Bit#(1)) wb_epochs[2] <-mkCReg(2,0);
69 Reg#(Bool) request_taken <-mkDReg(False);
70 Reg#(Bool) drop_request[2] <-mkCReg(2,False);
71 rule display_stuff;
72 `ifdef verbose $display($time,"\tDMEM: request_taken: %b drop_request: %b",request_taken,drop_request[0]); `endif
73 endrule
74 `ifdef MMU
75 (*conflict_free="ptw_to_dcache, send_translated_address"*)
76 (*conflict_free="send_translated_address,request_from_cpu.put"*)
77 (*conflict_free="send_translated_address,send_cache_index"*)
78 rule send_translated_address(rg_dtlb_metadata[1] matches tagged Valid .z);
79 rg_dtlb_metadata[1] <= tagged Invalid;
80 let x <- dtlb.send_ppn;
81 //From_Cpu_D#(`Reg_width,`DCACHE_WORD_SIZE) z = rg_dtlb_metadata;
82 let {y,epoch} = z;
83 y.address = x.address;
84 `ifdef verbose $display($time,"\tDMEM: physical address %h to DCACHE and is cacheable %b drop_request: %b", x.address, x.cacheable,drop_request[1]); `endif
85 dcache.physical_address(truncate(y.address), x.exception);//, y.mem_type, y.memory_data, y.transfer_size, y.atomic_op, unpack(y.signextend));
86 endrule
87
88 rule send_cache_index(rg_dtlb_metadata[1] matches tagged Valid .t);
89 let {z,epoch} = t;
90 let x <- dtlb.send_vaddress_for_cache_index;
91 dcache.virtual_address(x, z.mem_type, z.memory_data, z.transfer_size, `ifdef atomic z.atomic_op, `endif unpack(z.signextend),epoch);
92 endrule
93
94 rule ptw_to_dcache(rg_pte_pointer[1] matches tagged Valid .ptw_request);
95 `ifdef verbose $display($time,"\tDMEM: ptw request to DCACHE for address %h epochs: %b", ptw_request.address,epochs[1]); `endif
96 rg_serve_ptw <= True;
97 Bit#(`VADDR) addr = truncate(ptw_request.address);
98 Access_type page_access_type = Load;
99 Bit#(TMul#(`DCACHE_WORD_SIZE,8)) data = 0;
100 dcache.virtual_address(addr,Load, data, 'd3 `ifdef atomic , 5'b00100 `endif , True,epochs[1]);
101 dcache.physical_address(truncate(addr), tagged None);
102 rg_pte_pointer[1] <= tagged Invalid;
103 endrule
104
105 `endif
106
107 rule send_response_to_core;
108 wr_response_to_cpu[0] <= dcache.response_to_core;
109 endrule
110
111 /*======= Mandatory Interface to the core ================ */
112 interface request_from_cpu = interface Put
113 method Action put(Tuple2#(Memout,Bit#(1)) request) ;
114 let {req,epoch}=request;
115 `ifdef MMU
116 rg_dtlb_metadata[0] <= tagged Valid (tuple2(req,epoch));
117 dtlb.get_vaddr(DTLB_access{vaddr : req.address, ld_st_atomic : req.mem_type} `ifdef atomic ,req.atomic_op `endif );
118 `endif
119 dcache.virtual_address(truncate(req.address),req.mem_type, req.memory_data, req.transfer_size, `ifdef atomic req.atomic_op, `endif unpack(req.signextend),epoch);
120 `ifdef verbose $display($time,"\tDMEM: Taking request from CPU: ",fshow(request)); `endif
121 request_taken<=True;
122 endmethod
123 endinterface;
124
125 interface response_to_cpu = interface Get
126 method ActionValue#(Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS),Bit#(1)))) get if(!rg_serve_ptw);
127 Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS),Bit#(1))) response=tagged Invalid;
128 if(wr_response_to_cpu[2] matches tagged Valid .resp)begin
129 let {x,trap,y,epoch}=resp;
130 response=tagged Valid tuple4(x,trap,y,epoch);
131 if(trap matches tagged None)begin
132 end
133 else
134 epochs[0]<=~epochs[0];
135 end
136 return response;
137 endmethod
138 endinterface;
139
140 method Action flush();
141 dcache.flush_from_wb;
142 epochs[1]<=~epochs[1];
143 endmethod
144
145
146 method Bool stall_fetch =!dcache.init_complete;
147 /*=============================================== */
148
149 /*======= Mandatory Interface to the external bus ================ */
150 method ActionValue#(To_Memory#(`PADDR)) request_to_memory_read=dcache.read_request_to_memory;
151 method ActionValue#(To_Memory_Write) request_to_memory_write=dcache.write_request_to_memory;
152 method Action response_from_memory_read(From_Memory#(`DCACHE_WORD_SIZE) resp)=dcache.read_response_from_memory(resp);
153 method Action response_from_memory_write(From_Memory#(`DCACHE_WORD_SIZE) resp)=dcache.write_response_from_memory(resp);
154 /*=============================================== */
155 /*======= Interface to the DTLB ================ */
156 `ifdef MMU
157 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
158 dtlb.translation_protection_frm_csr(tlb_disable, per_bits, asid);
159 endmethod
160 interface to_PTW = dtlb.to_PTW;
161 interface refill_TLB = dtlb.refill_TLB;
162 method Action get_pte_pointer(Request_PTE_memory#(`Reg_width) pte);
163 rg_pte_pointer[0] <= tagged Valid pte;
164 endmethod
165 method Action fence_dtlb(Fence_VMA_type#(`VADDR) rsdata) = dtlb.fence_TLB(rsdata);
166 method ActionValue#(Bit#(`Reg_width)) send_pte if(isValid(dcache.response_to_core) && rg_serve_ptw);
167 rg_serve_ptw <= False;
168 Bit#(`Reg_width) data = 0;
169 if(dcache.response_to_core matches tagged Valid .resp) begin
170 let {x,y,perf,epoch} = resp;
171 data = x;
172 end
173 return data;
174 endmethod
175 `endif
176 /*=============================================== */
177 endmodule
178
179 endpackage