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 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
15 import defined_types::*;
17 import SpecialFIFOs::*;
21 `include "core_parameters.bsv"
23 `define TLB_entries 16
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;
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));
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);
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);
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);
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);
93 TLB_permissions perm_bits = TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0};
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;
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
114 `ifdef verbose_torture $display($time, "\t tlb_permissions valid ", fshow(tlb_permissions[i])); `endif
116 perm_bits = tlb_permissions[i];
117 pg_levels = tlb_levels[i];
120 cacheable = tlb_cacheable[i];
123 rg_levels[0] <= pg_levels;
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
129 // $display($time, "\t dTLB: page fault 1");
132 if(rg_chmod[1].prv==unpack(1) && perm_bits.u==1) begin
134 `ifdef verbose_torture $display($time, "\t dTLB: page fault 2"); `endif
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
141 `ifdef verbose_torture $display($time, "\t dTLB: page fault 3"); `endif
145 if(perm_bits.r==0) begin
147 `ifdef verbose_torture $display($time, "\t dTLB: page fault 4"); `endif
152 if(perm_bits.w==0 || perm_bits.d==0) begin
154 `ifdef verbose_torture $display($time, "\t dTLB: page fault 5"); `endif
155 // if(perm_bits.d==0)
157 // tlb_permissions[slot] <= perm_bits;
161 rg_cacheable[0] <= cacheable;
162 `ifdef verbose_torture $display($time, "\t dTLB: hit"); `endif
165 rg_handling_PTW[0] <= True;
166 `ifdef verbose_torture $display($time, "\t dTLB: miss"); `endif
168 rg_page_fault[0]<=page_fault;
169 `ifdef verbose_torture $display($time, "\t dTLB: The page fault is %b", page_fault); `endif
174 tlb_permissions[slot] <= perm_bits;
178 rule rl_flush_TLB(wr_flush);
182 rg_handling_PTW[1] <= False;
184 rg_page_fault[1] <= False;
185 rg_frm_ptw[1] <= False;
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 ));
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;
201 if(rg_levels[1]==0) begin
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};
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};
216 Bit#(paddr) paddress = {p_ppn,ff_page_offset.first()};
217 final_address = zeroExtend(paddress);
218 rg_frm_ptw[0] <= False;
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;
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;
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);
239 return From_TLB{exception : e, address : final_address, cacheable : rg_cacheable[1]};
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};
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
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};
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
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;
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
285 method Action flush(Bool _flush);
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
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
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};
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
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
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};
339 //method ActionValue#(Bool) page_fault if(rg_page_fault[1]);
341 // ff_page_offset.deq;
343 // rg_hit[1] <= False;
347 //method Action page_fault_frm_PTW if(rg_handling_PTW[0]);
348 // rg_page_fault[0] <= False;
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;
366 (*mutually_exclusive="refill_TLB_put, send_ppn"*)
368 module mkdTLB(Ifc_dTLB);
370 Ifc_TLB#(`ADDR,`VADDR,`PADDR,`OFFSET,`ASID) dtlb <- mkTLB();
372 method Action get_vaddr(DTLB_access#(`ADDR) addr `ifdef atomic , Bit#(5) atomic `endif );
373 dtlb.get_vaddr(addr `ifdef atomic ,atomic `endif );
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);
380 interface to_PTW = dtlb.to_PTW;
381 interface refill_TLB = dtlb.refill_TLB;
382 method Action flush(Bool _flush);
385 method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
386 dtlb.fence_TLB(rsdata);
389 //method ActionValue#(Bool) page_fault = dtlb.page_fault;
390 //method Action page_fault_frm_PTW = dtlb.page_fault_frm_PTW;