add core
[shakti-core.git] / src / core / iTLB.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 iTLB;
15 import defined_types::*;
16 import FIFO::*;
17 import SpecialFIFOs::*;
18 import GetPut::*;
19 import ConfigReg::*;
20 import MemoryMap:: *;
21
22 `include "defined_parameters.bsv"
23
24 `define TLB_entries 16
25
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;
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 Reg#(Bit#(TLog#(`TLB_entries))) rg_slot_to_replace <- mkReg(0);
87
88
89 rule rl_translation(!rg_handling_PTW[0] && !rg_tlb_disable && !(rg_chmod[1].prv==Machine)
90 && (rg_translation_mode[1]!=0));
91 Bit#(ppn) ppn = 0;
92 TLB_permissions perm_bits = TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0};
93 Bool hit = False;
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;
105 Integer slot = 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
112 ppn = tlb_ppn[i];
113 perm_bits = tlb_permissions[i];
114 pg_levels = tlb_levels[i];
115 hit = True;
116 slot = i;
117 cacheable = tlb_cacheable[i];
118 end
119 end
120 rg_levels[0] <= pg_levels;
121 if(hit) begin
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
125 page_fault=True;
126 end
127 end
128 else if(rg_chmod[1].prv==unpack(1) && perm_bits.u==1) begin
129 page_fault=True;
130 end
131 end
132 else begin
133 if(perm_bits.x!=1)
134 page_fault=True;
135 end
136 rg_ppn[0] <= ppn;
137 rg_cacheable[0] <= cacheable;
138 `ifdef verbose $display($time, "\t hit in iTLB"); `endif
139 end
140 else begin
141 rg_handling_PTW[0] <= True;
142 `ifdef verbose $display($time, "\t iTLB: miss"); `endif
143 end
144 rg_page_fault[0]<=page_fault;
145 if(!page_fault)
146 rg_hit[0]<=hit;
147 else begin
148 perm_bits.v = 0;
149 tlb_permissions[slot] <= perm_bits;
150 `ifdef verbose $display($time, "\t page fault in iTLB"); `endif
151 end
152 endrule
153
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]);
158 endmethod
159
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;
164 Bit#(ppn) p_ppn = 0;
165 if(rg_levels[1]==0) begin
166 p_ppn = rg_ppn[1];
167 end
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};
172 end
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};
177 end
178 if(rg_hit[1]) begin
179 rg_hit[1] <= False;
180 Bit#(paddr) paddress = {p_ppn,ff_page_offset.first()};
181 final_address = zeroExtend(paddress);
182 //rg_frm_ptw[1] <= False;
183 end
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;
191 end
192 else begin
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);
196 end
197 ff_page_offset.deq;
198 ff_vpn.deq;
199 return From_TLB{exception : e, address : final_address, cacheable : rg_cacheable[1]};
200 endmethod
201
202 //method Bit#(vaddr) send_vaddress_for_cache_index if(rg_frm_ptw[0]);
203 // return {ff_vpn.first, ff_page_offset.first};
204 //endmethod
205
206
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
213 endmethod
214
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};
218 endmethod
219 endinterface;
220
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);
228 if(!x) begin
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;
236 end
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
240 endmethod
241 endinterface;
242
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
256 end
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
260 end
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};
269 end
270 end
271 endmethod
272
273 endmodule
274
275 interface Ifc_iTLB;
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;
285 endinterface
286
287 (*synthesize*)
288 module mkiTLB(Ifc_iTLB);
289
290 Ifc_TLB#(`ADDR,`VADDR,`PADDR,`OFFSET,`ASID) itlb <- mkTLB();
291 method Action get_vaddr(Bit#(`ADDR) addr);
292 itlb.get_vaddr(addr);
293 endmethod
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);
298 endmethod
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);
303 endmethod
304 //method ActionValue#(Bool) page_fault = itlb.page_fault;
305 //method Action page_fault_frm_PTW = itlb.page_fault_frm_PTW;
306 endmodule
307 endpackage