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::*;
22 `include "defined_parameters.bsv"
24 `define TLB_entries 16
26 interface Ifc_TLB#(numeric type data_width, numeric type vaddr, numeric type paddr, numeric type page_size, numeric type asid_width);
27 method Action get_vaddr(Bit#(data_width) addr);
28 method ActionValue#(From_TLB#(data_width)) send_ppn;
29 //method Bit#(vaddr) send_vaddress_for_cache_index;
30 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,asid_width)) asid);
31 interface Get#(Request_PPN_PTW#(vaddr,page_size)) to_PTW;
32 interface Put#(Tuple2#(Bool,To_TLB#(paddr,page_size,asid_width))) refill_TLB;
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 Reg#(Bit#(TLog#(`TLB_entries))) rg_slot_to_replace <- mkReg(0);
89 rule rl_translation(!rg_handling_PTW[0] && !rg_tlb_disable && !(rg_chmod[1].prv==Machine)
90 && (rg_translation_mode[1]!=0));
92 TLB_permissions perm_bits = TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0};
94 Bool page_fault = False;
95 Bool cacheable = False;
96 Bit#(vpn) vpn_bits = ff_vpn.first;
97 Bit#(vpn_split) lv_vpn_split= 0;
98 Bit#(intermediate1) lv_intermediate1 = 0;
99 Bit#(intermediate2) lv_intermediate2= 0;
100 Bit#(vpn) mask1 = {'1,lv_vpn_split};
101 Bit#(vpn) vpnmask1 = vpn_bits & mask1;
102 Bit#(vpn) mask2 = {'1,lv_intermediate1};
103 Bit#(vpn) vpnmask2 = vpn_bits & mask2;
104 Bit#(2) pg_levels = 0;
106 `ifdef verbose $display($time, "\tThe acquired VPN in iTLB %h", ff_vpn.first); `endif
107 for(Integer i = 0; i < `TLB_entries; i = i + 1) begin
108 if((vpn_bits==tlb_vpn[i] && tlb_levels[i]==0
109 || ((vpnmask1==(tlb_vpn[i] & mask1)) && tlb_levels[i]==1)
110 || ((vpnmask2==(tlb_vpn[i] & mask2)) && tlb_levels[i]==2))
111 && (rg_asid[1]==tlb_asid[i] || tlb_permissions[i].g==1) && tlb_permissions[i].v==1) begin
113 perm_bits = tlb_permissions[i];
114 pg_levels = tlb_levels[i];
117 cacheable = tlb_cacheable[i];
120 rg_levels[0] <= pg_levels;
122 if(rg_chmod[1].sum==0) begin
123 if(rg_chmod[1].mprv==1) begin
124 if(rg_chmod[1].mpp==unpack(1) && perm_bits.u==1) begin
128 else if(rg_chmod[1].prv==unpack(1) && perm_bits.u==1) begin
137 rg_cacheable[0] <= cacheable;
138 `ifdef verbose $display($time, "\t hit in iTLB"); `endif
141 rg_handling_PTW[0] <= True;
142 `ifdef verbose $display($time, "\t iTLB: miss"); `endif
144 rg_page_fault[0]<=page_fault;
149 tlb_permissions[slot] <= perm_bits;
150 `ifdef verbose $display($time, "\t page fault in iTLB"); `endif
154 method Action get_vaddr(Bit#(data_width) vaddr);
155 `ifdef verbose $display($time, "\t vpn obtained in TLB"); `endif
156 ff_vpn.enq(vaddr[v_vaddr-1: v_page_offset]);
157 ff_page_offset.enq(vaddr[v_page_offset-1:0]);
160 method ActionValue#(From_TLB#(data_width)) send_ppn if(rg_hit[1] || rg_tlb_disable
161 || (rg_chmod[1].prv==Machine) || rg_page_fault[1] || (rg_translation_mode[1]==0));
162 Trap_type e = tagged None;
163 Bit#(data_width) final_address;
165 if(rg_levels[1]==0) begin
168 else if(rg_levels[1]==1) begin
169 Bit#(TSub#(ppn,vpn_split)) lv_ppn_split = rg_ppn[1][v_ppn-1:v_vpn_split];
170 Bit#(vpn_split) lv_vpn_split = ff_vpn.first[v_vpn_split-1:0];
171 p_ppn = {lv_ppn_split,lv_vpn_split};
173 else if(rg_levels[1]==2) begin
174 Bit#(TSub#(ppn,intermediate1)) lv_ppn_split = rg_ppn[1][v_ppn-1:v_intermediate1];
175 Bit#(intermediate1) lv_vpn_split = ff_vpn.first[v_intermediate1-1:0];
176 p_ppn = {lv_ppn_split,lv_vpn_split};
180 Bit#(paddr) paddress = {p_ppn,ff_page_offset.first()};
181 final_address = zeroExtend(paddress);
182 //rg_frm_ptw[1] <= False;
184 else if(rg_page_fault[1]) begin
185 `ifdef verbose $display($time, "\t Instruction Page Fault"); `endif
186 e = tagged Exception Inst_pagefault;
187 Bit#(vaddr) paddress = {ff_vpn.first(),ff_page_offset.first()};
188 final_address = zeroExtend(paddress);
189 rg_page_fault[1] <= False;
190 //rg_frm_ptw[1] <= False;
193 `ifdef verbose $display($time, "\t Bypass iTLB"); `endif
194 Bit#(vaddr) paddress = {ff_vpn.first(),ff_page_offset.first()};
195 final_address = zeroExtend(paddress);
199 return From_TLB{exception : e, address : final_address, cacheable : rg_cacheable[1]};
202 //method Bit#(vaddr) send_vaddress_for_cache_index if(rg_frm_ptw[0]);
203 // return {ff_vpn.first, ff_page_offset.first};
207 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,asid_width)) asid);
208 rg_tlb_disable <= unpack(tlb_disable);
209 rg_asid[0] <= asid[v_asid_width-1:0];
210 rg_translation_mode[0] <= asid[v_asid_width+3:v_asid_width];
211 rg_chmod[0] <= per_bits;
212 `ifdef verbose $display($time, "\t ITLB: 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
215 interface to_PTW = interface Get
216 method ActionValue#(Request_PPN_PTW#(vaddr,page_size)) get if(rg_handling_PTW[1] && !rg_page_fault[1]);
217 return Request_PPN_PTW{ vpn : ff_vpn.first(), page_type : Execution};
221 interface refill_TLB = interface Put
222 method Action put(Tuple2#(Bool, To_TLB#(paddr,page_size,asid_width)) tlb_fill) if(rg_handling_PTW[0]);
223 let {x,tlb_structure} = tlb_fill;
224 rg_page_fault[0] <= x;
225 Bit#(paddr) paddress= {tlb_structure.ppn,ff_page_offset.first};
226 Bit#(data_width) new_address = zeroExtend(paddress);
227 Bool cacheable = True; //!is_IO_Addr(new_address);
229 rg_slot_to_replace <= rg_slot_to_replace + 1;
230 tlb_vpn[rg_slot_to_replace] <= ff_vpn.first();
231 tlb_ppn[rg_slot_to_replace] <= tlb_structure.ppn;
232 tlb_permissions[rg_slot_to_replace] <= tlb_structure.tlb_perm;
233 tlb_levels[rg_slot_to_replace] <= tlb_structure.levels;
234 tlb_asid[rg_slot_to_replace] <= tlb_structure.asid;
235 tlb_cacheable[rg_slot_to_replace] <= cacheable;
237 rg_handling_PTW[0] <= False;
238 //rg_frm_ptw[0] <= True;
239 `ifdef verbose $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
243 method Action fence_TLB(Fence_VMA_type#(vaddr) rsdata);
244 Bool flush_address = False;
245 Bool flush_address_space = False;
246 Bit#(vpn_split) lv_vpn_split= 0;
247 Bit#(intermediate1) lv_intermediate1 = 0;
248 Bit#(intermediate2) lv_intermediate2= 0;
249 Bit#(vpn) mask1 = {'1,lv_vpn_split};
250 Bit#(vpn) vpnmask1 = rsdata.rs1[v_vaddr-1:v_page_offset] & mask1;
251 Bit#(vpn) mask2 = {'1,lv_intermediate1};
252 Bit#(vpn) vpnmask2 = rsdata.rs1[v_vaddr-1:v_page_offset] & mask2;
253 if(rsdata.rs1!=0) begin
254 flush_address = True;
255 `ifdef verbose $display($time, "\t iTLB address flush %h", rsdata.rs1); `endif
257 if(rsdata.rs2!=0) begin
258 flush_address_space = True;
259 `ifdef verbose $display($time, "\t iTLB address space flush %h", rsdata.rs2); `endif
261 for(Integer i = 0; i < `TLB_entries; i = i+1) begin
262 if(((flush_address && ((rsdata.rs1[v_vaddr-1:v_page_offset] == tlb_vpn[i] && tlb_levels[i]==0)
263 || (vpnmask1 == (tlb_vpn[i] & mask1) && tlb_levels[i]==1)
264 || (vpnmask2 == (tlb_vpn[i] & mask2) && tlb_levels[i]==2)))
265 || (flush_address_space && rsdata.rs2[v_asid_width-1:0] == tlb_asid[i]))
266 || (!flush_address && !flush_address_space)) begin
267 `ifdef verbose $display($time, "\t iTLB entry %d with vpn %h removed",i, tlb_vpn[i]); `endif
268 tlb_permissions[i] <= TLB_permissions{v : 0, r : 0, w : 0, x : 0, u : 0, g : 0, a : 0, d : 0};
276 method Action get_vaddr(Bit#(`ADDR) addr);
277 method ActionValue#(From_TLB#(`ADDR)) send_ppn;
278 //method Bit#(`VADDR) send_vaddress_for_cache_index;
279 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
280 interface Get#(Request_PPN_PTW#(`VADDR,`OFFSET)) to_PTW;
281 interface Put#(Tuple2#(Bool,To_TLB#(`PADDR,`OFFSET,`ASID))) refill_TLB;
282 method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
283 //method ActionValue#(Bool) page_fault;
284 //method Action page_fault_frm_PTW;
288 module mkiTLB(Ifc_iTLB);
290 Ifc_TLB#(`ADDR,`VADDR,`PADDR,`OFFSET,`ASID) itlb <- mkTLB();
291 method Action get_vaddr(Bit#(`ADDR) addr);
292 itlb.get_vaddr(addr);
294 method ActionValue#(From_TLB#(`ADDR)) send_ppn = itlb.send_ppn;
295 //method Bit#(`VADDR) send_vaddress_for_cache_index = itlb.send_vaddress_for_cache_index;
296 method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
297 itlb.translation_protection_frm_csr(tlb_disable,per_bits,asid);
299 interface to_PTW = itlb.to_PTW;
300 interface refill_TLB = itlb.refill_TLB;
301 method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
302 itlb.fence_TLB(rsdata);
304 //method ActionValue#(Bool) page_fault = itlb.page_fault;
305 //method Action page_fault_frm_PTW = itlb.page_fault_frm_PTW;