add ClintBase
[shakti-core.git] / src / core / dTLB.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 dTLB;
15 import defined_types::*;
16 import FIFO::*;
17 import SpecialFIFOs::*;
18 import GetPut::*;
19 import ConfigReg::*;
20
21 `include "core_parameters.bsv"
22
23 `define TLB_entries 16
24
25 interface Ifc_TLB#(numeric type data_width, numeric type vaddr, numeric type paddr, numeric type page_size, numeric type asid_width);
26 method Action get_vaddr(DTLB_access#(data_width) addr `ifdef atomic , Bit#(5) atomic `endif );
27 method ActionValue#(From_TLB#(data_width)) send_ppn;
28 method ActionValue#(Bit#(vaddr)) send_vaddress_for_cache_index;
29 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,asid_width)) asid); //TODO parameterise this
30 interface Get#(Request_PPN_PTW#(vaddr,page_size)) to_PTW;
31 interface Put#(Tuple2#(Bool,To_TLB#(paddr,page_size,asid_width))) refill_TLB;
32 method Action flush(Bool _flush);
33 method Action fence_TLB(Fence_VMA_type#(vaddr) rsdata);
34 //method ActionValue#(Bool) page_fault;
35 //method Action page_fault_frm_PTW;
36 endinterface
37
38 module mkTLB(Ifc_TLB#(data_width,vaddr,paddr,page_size,asid_width))
39 provisos( Add#(vpn, page_size, vaddr),
40 Mul#(8, num_bytes, data_width),
41 Log#(num_bytes, byte_addressable_bits),
42 Add#(vpn_split,byte_addressable_bits, page_size),
43 Mul#(2,vpn_split,intermediate1),
44 Mul#(3,vpn_split,intermediate2),
45 Add#(a_, paddr, data_width),
46 Add#(b_, vaddr, data_width),
47 Add#(c_, vpn_split, vpn),
48 Add#(d_, intermediate1, vpn),
49 Add#(e_, intermediate2, vpn),
50 Add#(ppn, page_size, paddr));
51
52 let v_vaddr = valueOf(vaddr);
53 let v_vpn = valueOf(vpn);
54 let v_ppn = valueOf(ppn);
55 let v_page_offset = valueOf(page_size);
56 let v_asid_width = valueOf(asid_width);
57 let v_vpn_split = valueOf(vpn_split);
58 let v_intermediate1 = valueOf(intermediate1);
59
60 Reg#(Bit#(vpn)) tlb_vpn[`TLB_entries];
61 Reg#(Bit#(ppn)) tlb_ppn[`TLB_entries];
62 Reg#(TLB_permissions) tlb_permissions[`TLB_entries];
63 Reg#(Bit#(asid_width)) tlb_asid[`TLB_entries];
64 Reg#(Bool) tlb_cacheable[`TLB_entries];
65 Reg#(Bit#(2)) tlb_levels[`TLB_entries];
66 for(Integer i = 0; i < `TLB_entries; i=i+1) begin
67 tlb_vpn[i] <- mkReg(0);
68 tlb_ppn[i] <- mkReg(0);
69 tlb_permissions[i] <- mkReg(TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0});
70 tlb_levels[i] <- mkReg(0);
71 tlb_cacheable[i] <- mkReg(True);
72 end
73 FIFO#(Bit#(vpn)) ff_vpn <- mkBypassFIFO();
74 FIFO#(Bit#(page_size)) ff_page_offset <- mkBypassFIFO();
75 Reg#(Chmod) rg_chmod[2] <- mkCReg(2,Chmod { mprv : 0, mxr : 0, sum : 0, mpp : unpack(0), prv : unpack(0)});
76 Reg#(Bool) rg_page_fault[2] <- mkCReg(2,False);
77 Reg#(Bool) rg_hit[2] <- mkCReg(2,False);
78 Reg#(Bit#(2)) rg_levels[2] <- mkCReg(2,0);
79 Reg#(Bool) rg_handling_PTW[2] <- mkCReg(2,False);
80 Reg#(Bool) rg_tlb_disable <- mkConfigReg(False);
81 Reg#(Bool) rg_frm_ptw[2] <- mkCReg(2,False);
82 Reg#(Bit#(ppn)) rg_ppn[2] <- mkCReg(2,0);
83 Reg#(Bool) rg_cacheable[2] <- mkCReg(2,True);
84 Reg#(Bit#(asid_width)) rg_asid[2] <- mkCReg(2,0);
85 Reg#(Bit#(4)) rg_translation_mode[2] <- mkCReg(2,0);
86 FIFO#(Tuple2#(Access_type,Bit#(5))) ff_access <- mkBypassFIFO();
87 Reg#(Bit#(TLog#(`TLB_entries))) rg_slot_to_replace <- mkReg(0);
88 Wire#(Bool) wr_flush <- mkDWire(False);
89
90 rule rl_translation(!rg_handling_PTW[0] && !rg_tlb_disable && (rg_chmod[1].prv!=Machine) && !rg_page_fault[0]
91 && (rg_translation_mode[1]!=0) && !wr_flush && tpl_1(ff_access.first())!=Fence);
92 Bit#(ppn) ppn = 0;
93 TLB_permissions perm_bits = TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0};
94 Bool hit = False;
95 Bool page_fault = False;
96 Bool cacheable = False;
97 Bit#(vpn) vpn_bits = ff_vpn.first;
98 Bit#(vpn_split) lv_vpn_split= 0;
99 Bit#(intermediate1) lv_intermediate1 = 0;
100 Bit#(intermediate2) lv_intermediate2= 0;
101 Bit#(vpn) mask1 = {'1,lv_vpn_split};
102 Bit#(vpn) vpnmask1 = vpn_bits & mask1;
103 Bit#(vpn) mask2 = {'1,lv_intermediate1};
104 Bit#(vpn) vpnmask2 = vpn_bits & mask2;
105 Bit#(2) pg_levels = 0;
106 Integer slot = 0;
107 `ifdef verbose_torture $display($time, "\tThe acquired VPN in iTLB %h", ff_vpn.first); `endif
108 for(Integer i = 0; i < `TLB_entries; i = i + 1) begin
109 if((vpn_bits==tlb_vpn[i] && tlb_levels[i]==0
110 || ((vpnmask1==(tlb_vpn[i] & mask1)) && tlb_levels[i]==1)
111 || ((vpnmask2==(tlb_vpn[i] & mask2)) && tlb_levels[i]==2))
112 && (rg_asid[1]==tlb_asid[i] || tlb_permissions[i].g==1) && tlb_permissions[i].v==1) begin
113
114 `ifdef verbose_torture $display($time, "\t tlb_permissions valid ", fshow(tlb_permissions[i])); `endif
115 ppn = tlb_ppn[i];
116 perm_bits = tlb_permissions[i];
117 pg_levels = tlb_levels[i];
118 hit = True;
119 slot = i;
120 cacheable = tlb_cacheable[i];
121 end
122 end
123 rg_levels[0] <= pg_levels;
124 if(hit) begin
125 if(rg_chmod[1].sum==0) begin
126 //if(rg_chmod[1].mprv==1) begin
127 // if(rg_chmod[1].mpp==unpack(1) && perm_bits.u==1) begin
128 // page_fault=True;
129 // $display($time, "\t dTLB: page fault 1");
130 // end
131 //end
132 if(rg_chmod[1].prv==unpack(1) && perm_bits.u==1) begin
133 page_fault=True;
134 `ifdef verbose_torture $display($time, "\t dTLB: page fault 2"); `endif
135 end
136 end
137 if(tpl_1(ff_access.first())==Load `ifdef atomic || (tpl_1(ff_access.first)==Atomic && tpl_2(ff_access.first)[3:0]=='b0101) `endif ) begin
138 if(rg_chmod[1].mxr==1) begin
139 if(perm_bits.x==0 || perm_bits.r==0) begin
140 page_fault=True;
141 `ifdef verbose_torture $display($time, "\t dTLB: page fault 3"); `endif
142 end
143 end
144 else begin
145 if(perm_bits.r==0) begin
146 page_fault=True;
147 `ifdef verbose_torture $display($time, "\t dTLB: page fault 4"); `endif
148 end
149 end
150 end
151 else begin
152 if(perm_bits.w==0 || perm_bits.d==0) begin
153 page_fault=True;
154 `ifdef verbose_torture $display($time, "\t dTLB: page fault 5"); `endif
155 // if(perm_bits.d==0)
156 // perm_bits.v = 0;
157 // tlb_permissions[slot] <= perm_bits;
158 end
159 end
160 rg_ppn[0] <= ppn;
161 rg_cacheable[0] <= cacheable;
162 `ifdef verbose_torture $display($time, "\t dTLB: hit"); `endif
163 end
164 else begin
165 rg_handling_PTW[0] <= True;
166 `ifdef verbose_torture $display($time, "\t dTLB: miss"); `endif
167 end
168 rg_page_fault[0]<=page_fault;
169 `ifdef verbose_torture $display($time, "\t dTLB: The page fault is %b", page_fault); `endif
170 if(!page_fault)
171 rg_hit[0]<=hit;
172 else begin
173 perm_bits.v = 0;
174 tlb_permissions[slot] <= perm_bits;
175 end
176 endrule
177
178 rule rl_flush_TLB(wr_flush);
179 ff_vpn.deq;
180 ff_page_offset.deq;
181 ff_access.deq;
182 rg_handling_PTW[1] <= False;
183 rg_hit[1] <= False;
184 rg_page_fault[1] <= False;
185 rg_frm_ptw[1] <= False;
186 endrule
187
188 method Action get_vaddr(DTLB_access#(data_width) addr `ifdef atomic , Bit#(5) atomic `endif );
189 `ifdef verbose_torture $display($time, "\t dTLB: Initiated translation through dTLB and disable is %b", rg_tlb_disable); `endif
190 ff_vpn.enq(addr.vaddr[v_vaddr-1: v_page_offset]);
191 ff_page_offset.enq(addr.vaddr[v_page_offset-1:0]);
192 ff_access.enq(tuple2(addr.ld_st_atomic, `ifdef atomic atomic `else 0 `endif ));
193 endmethod
194
195 method ActionValue#(From_TLB#(data_width)) send_ppn if(rg_hit[1] || rg_tlb_disable
196 || (rg_chmod[1].prv==Machine) || rg_page_fault[1] || (rg_translation_mode[1]==0)
197 || tpl_1(ff_access.first())==Fence);
198 Trap_type e = tagged None;
199 Bit#(data_width) final_address;
200 Bit#(ppn) p_ppn = 0;
201 if(rg_levels[1]==0) begin
202 p_ppn = rg_ppn[1];
203 end
204 else if(rg_levels[1]==1) begin
205 Bit#(TSub#(ppn,vpn_split)) lv_ppn_split = rg_ppn[1][v_ppn-1:v_vpn_split];
206 Bit#(vpn_split) lv_vpn_split = ff_vpn.first[v_vpn_split-1:0];
207 p_ppn = {lv_ppn_split,lv_vpn_split};
208 end
209 else if(rg_levels[1]==2) begin
210 Bit#(TSub#(ppn,intermediate1)) lv_ppn_split = rg_ppn[1][v_ppn-1:v_intermediate1];
211 Bit#(intermediate1) lv_vpn_split = ff_vpn.first[v_intermediate1-1:0];
212 p_ppn = {lv_ppn_split,lv_vpn_split};
213 end
214 if(rg_hit[1]) begin
215 rg_hit[1] <= False;
216 Bit#(paddr) paddress = {p_ppn,ff_page_offset.first()};
217 final_address = zeroExtend(paddress);
218 rg_frm_ptw[0] <= False;
219 end
220 else if(rg_page_fault[1]) begin
221 `ifdef verbose_torture $display($time, "\t DTLB Page Fault"); `endif
222 if(tpl_1(ff_access.first())== Load `ifdef atomic || (tpl_1(ff_access.first)==Atomic && tpl_2(ff_access.first)[3:0]=='b0101) `endif )
223 e = tagged Exception Load_pagefault;
224 else
225 e = tagged Exception Store_pagefault;
226 Bit#(vaddr) paddress = {ff_vpn.first(),ff_page_offset.first()};
227 final_address = zeroExtend(paddress);
228 rg_page_fault[1] <= False;
229 rg_frm_ptw[0] <= False;
230 end
231 else begin
232 `ifdef verbose_torture $display($time, "\t dTLB: Bypass"); `endif
233 Bit#(vaddr) paddress = {ff_vpn.first(),ff_page_offset.first()};
234 final_address = zeroExtend(paddress);
235 end
236 ff_page_offset.deq;
237 ff_vpn.deq;
238 ff_access.deq;
239 return From_TLB{exception : e, address : final_address, cacheable : rg_cacheable[1]};
240 endmethod
241
242 method ActionValue#(Bit#(vaddr)) send_vaddress_for_cache_index if(rg_frm_ptw[0]);
243 rg_frm_ptw[0] <= False;
244 return {ff_vpn.first, ff_page_offset.first};
245 endmethod
246
247 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,asid_width)) asid);
248 rg_tlb_disable <= unpack(tlb_disable);
249 rg_asid[0] <= asid[v_asid_width-1:0];
250 rg_translation_mode[0] <= asid[v_asid_width+3:v_asid_width];
251 per_bits.prv=per_bits.mprv==1?per_bits.mpp:per_bits.prv;
252 rg_chmod[0] <= per_bits;
253 `ifdef verbose_torture $display($time, "\t DTLB: mprv %b mxr %b sum %b mpp %b prv %b", per_bits.mprv, per_bits.mxr, per_bits.sum, pack(per_bits.mpp), pack(per_bits.prv)); `endif
254 endmethod
255
256 interface to_PTW = interface Get
257 method ActionValue#(Request_PPN_PTW#(vaddr,page_size)) get if(rg_handling_PTW[1] && !rg_page_fault[1]);
258 return Request_PPN_PTW{ vpn : ff_vpn.first(), page_type : (tpl_1(ff_access.first())==Load `ifdef atomic || (tpl_1(ff_access.first)==Atomic && tpl_2(ff_access.first)[3:0]=='b0101) `endif )?Load:Store};
259 endmethod
260 endinterface;
261
262 interface refill_TLB = interface Put
263 method Action put(Tuple2#(Bool, To_TLB#(paddr,page_size,asid_width)) tlb_fill) if(rg_handling_PTW[0]);
264 let {x,tlb_structure} = tlb_fill;
265 rg_page_fault[1] <= x;
266 Bit#(paddr) paddress= {tlb_structure.ppn,ff_page_offset.first};
267 Bit#(data_width) new_address = zeroExtend(paddress);
268 Bool cacheable = True; //!is_IO_Addr(zeroExtend(new_address)); TODO
269 if(!x) begin
270 rg_slot_to_replace <= rg_slot_to_replace + 1;
271 tlb_vpn[rg_slot_to_replace] <= ff_vpn.first();
272 tlb_ppn[rg_slot_to_replace] <= tlb_structure.ppn;
273 tlb_permissions[rg_slot_to_replace] <= tlb_structure.tlb_perm;
274 tlb_levels[rg_slot_to_replace] <= tlb_structure.levels;
275 tlb_asid[rg_slot_to_replace] <= tlb_structure.asid;
276 tlb_cacheable[rg_slot_to_replace] <= cacheable;
277 end
278 rg_handling_PTW[0] <= False;
279 rg_frm_ptw[0] <= True;
280 `ifdef verbose_torture $display($time, "\t Filling TLB in slot %d with vpn %h with page levels i %d", rg_slot_to_replace, ff_vpn.first(), tlb_structure.levels); `endif
281 `ifdef verbose_torture $display($time, " dTLB: Filling TLB and page fault is %b", x); `endif
282 endmethod
283 endinterface;
284
285 method Action flush(Bool _flush);
286 wr_flush <= _flush;
287 endmethod
288
289 method Action fence_TLB(Fence_VMA_type#(vaddr) rsdata);
290 Bool flush_address = False;
291 Bool flush_address_space = False;
292 Bit#(vpn_split) lv_vpn_split= 0;
293 Bit#(intermediate1) lv_intermediate1 = 0;
294 Bit#(intermediate2) lv_intermediate2= 0;
295 Bit#(vpn) mask1 = {'1,lv_vpn_split};
296 Bit#(vpn) vpnmask1 = rsdata.rs1[v_vaddr-1:v_page_offset] & mask1;
297 Bit#(vpn) mask2 = {'1,lv_intermediate1};
298 Bit#(vpn) vpnmask2 = rsdata.rs1[v_vaddr-1:v_page_offset] & mask2;
299 if(rsdata.rs1!=0) begin
300 flush_address = True;
301 `ifdef verbose_torture $display($time, "\t dTLB address flush %h", rsdata.rs1); `endif
302 end
303 if(rsdata.rs2!=0) begin
304 flush_address_space = True;
305 `ifdef verbose_torture $display($time, "\t dTLB address space flush %h", rsdata.rs2); `endif
306 end
307 for(Integer i = 0; i < `TLB_entries; i = i+1) begin
308 if(((flush_address && ((rsdata.rs1[v_vaddr-1:v_page_offset] == tlb_vpn[i] && tlb_levels[i]==0)
309 || (vpnmask1 == (tlb_vpn[i] & mask1) && tlb_levels[i]==1)
310 || (vpnmask2 == (tlb_vpn[i] & mask2) && tlb_levels[i]==2)))
311 || (flush_address_space && rsdata.rs2[v_asid_width-1:0] == tlb_asid[i]))
312 || (!flush_address && !flush_address_space)) begin
313 `ifdef verbose_torture $display($time, "\t dTLB entry %d with vpn %h removed",i, tlb_vpn[i]); `endif
314 tlb_permissions[i] <= TLB_permissions{v : 0, r : 0, w : 0, x : 0, u : 0, g : 0, a : 0, d : 0};
315 end
316 end
317 endmethod
318
319 //method Action fence_TLB(Fence_VMA_type#(data_width) rsdata);
320 // Bool flush_address = False;
321 // Bool flush_address_space = False;
322 // if(rsdata.rs1!=0) begin
323 // flush_address = True;
324 // `ifdef verbose_torture $display($time, "\t dTLB address flush %h", rsdata.rs1); `endif
325 // end
326 // if(rsdata.rs2!=0) begin
327 // flush_address_space = True;
328 // `ifdef verbose_torture $display($time, "\t dTLB address space flush %h", rsdata.rs2); `endif
329 // end
330 // for(Integer i = 0; i < `TLB_entries; i = i+1) begin
331 // if(((flush_address && rsdata.rs1[v_vaddr-1:v_page_offset] == tlb_vpn[i])
332 // || (flush_address_space && rsdata.rs2[v_asid_width-1:0] == tlb_asid[i]))
333 // || (flush_address && flush_address_space)) begin
334 // tlb_permissions[i] <= TLB_permissions{v : 0, r : 0, w : 0, x : 0, u : 0, g : 0, a : 0, d : 0};
335 // end
336 // end
337 //endmethod
338
339 //method ActionValue#(Bool) page_fault if(rg_page_fault[1]);
340 // ff_vpn.deq;
341 // ff_page_offset.deq;
342 // ff_access.deq;
343 // rg_hit[1] <= False;
344 // return True;
345 //endmethod
346
347 //method Action page_fault_frm_PTW if(rg_handling_PTW[0]);
348 // rg_page_fault[0] <= False;
349 //endmethod
350
351 endmodule
352
353 interface Ifc_dTLB;
354 method Action get_vaddr(DTLB_access#(`ADDR) addr `ifdef atomic , Bit#(5) atomic `endif );
355 method ActionValue#(From_TLB#(`ADDR)) send_ppn;
356 method ActionValue#(Bit#(`VADDR)) send_vaddress_for_cache_index;
357 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
358 interface Get#(Request_PPN_PTW#(`VADDR,`OFFSET)) to_PTW;
359 interface Put#(Tuple2#(Bool, To_TLB#(`PADDR,`OFFSET,`ASID))) refill_TLB;
360 method Action flush(Bool _flush);
361 method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
362 //method ActionValue#(Bool) page_fault;
363 //method Action page_fault_frm_PTW;
364 endinterface
365
366 (*mutually_exclusive="refill_TLB_put, send_ppn"*)
367 (*synthesize*)
368 module mkdTLB(Ifc_dTLB);
369
370 Ifc_TLB#(`ADDR,`VADDR,`PADDR,`OFFSET,`ASID) dtlb <- mkTLB();
371
372 method Action get_vaddr(DTLB_access#(`ADDR) addr `ifdef atomic , Bit#(5) atomic `endif );
373 dtlb.get_vaddr(addr `ifdef atomic ,atomic `endif );
374 endmethod
375 method ActionValue#(From_TLB#(`ADDR)) send_ppn = dtlb.send_ppn;
376 method ActionValue#(Bit#(`VADDR)) send_vaddress_for_cache_index = dtlb.send_vaddress_for_cache_index;
377 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
378 dtlb.translation_protection_frm_csr(tlb_disable,per_bits,asid);
379 endmethod
380 interface to_PTW = dtlb.to_PTW;
381 interface refill_TLB = dtlb.refill_TLB;
382 method Action flush(Bool _flush);
383 dtlb.flush(_flush);
384 endmethod
385 method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
386 dtlb.fence_TLB(rsdata);
387 endmethod
388
389 //method ActionValue#(Bool) page_fault = dtlb.page_fault;
390 //method Action page_fault_frm_PTW = dtlb.page_fault_frm_PTW;
391 endmodule
392
393 endpackage