add core
[shakti-core.git] / src / core / PTWalk.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 PTWalk;
15
16 import ConfigReg:: *;
17 import defined_types::*;
18 import GetPut::*;
19
20
21 function TLB_permissions ptw_to_tlb_perms(Bit#(10) perms);
22 return TLB_permissions { v : perms[0],
23 r : perms[1],
24 w : perms[2],
25 x : perms[3],
26 u : perms[4],
27 g : perms[5],
28 a : perms[6],
29 d : perms[7]};
30 endfunction
31
32 //interface Ifc_TLB#(numeric type vaddr, numeric type page_size, numeric type paddr, numeric type asid_width);
33 // method Action get_vpn(Request_PPN_PTW#(vaddr,page_size) req);
34 // method ActionValue#(Response_PPN_TLB#(paddr, page_size, asid_width)) send_ppn;
35 //endinterface
36
37 interface Ifc_memory#(numeric type data_width);
38 method ActionValue#(Request_PTE_memory#(data_width)) send_PTE_pointer;
39 method Action get_PTE(Bit#(data_width) pte);
40 endinterface
41
42 interface Ifc_PTWalk#(numeric type data_width,
43 numeric type vaddr,
44 numeric type paddr,
45 numeric type real_paddr,
46 numeric type asid_width,
47 numeric type page_size);
48 interface Put#(Request_PPN_PTW#(vaddr,page_size)) frm_TLB;
49 interface Get#(Tuple2#(Bool,To_TLB#(real_paddr,page_size,asid_width))) to_TLB;
50 interface Ifc_memory#(data_width) ifc_memory;
51 method Action satp_frm_csr(Bit#(data_width) satp);
52 method Action flush(Translation_type _flush);
53 //method Bool ptwalkdone;
54 //method Maybe#(Translation_type) page_fault;
55 endinterface
56
57 module mkPTWalk(Ifc_PTWalk#(data_width,vaddr_width,paddr_width, real_paddr, asid_width,page_size_bits))
58 provisos(
59 Mul#(8,no_of_bytes, data_width),
60 Log#(no_of_bytes, addressable_bits),
61 Log#(data_width, data_width_bits),
62 Add#(vpn_width, page_size_bits, vaddr_width),
63 Add#(vpn_split, addressable_bits, page_size_bits),
64 Add#(ppn_width, page_size_bits, paddr_width),
65 Add#(real_ppn_width, page_size_bits, real_paddr),
66 Mul#(vpn_split, levels, vpn_width),
67 Add#(10, ppn_width, ppn_perm),
68 Add#(y_, ppn_width, data_width),
69 Add#(x_, real_ppn_width, data_width),
70 Add#(a_, ppn_perm, data_width),
71 Add#(b_, paddr_width, data_width),
72 Add#(c_, 10, data_width),
73 Add#(d_, vpn_width, data_width),
74 Add#(1, sub_levels, levels)
75 );
76
77 let v_data_width = valueOf(data_width);
78 let v_data_width_bits = valueOf(data_width_bits);
79 let v_vpn_width = valueOf(vpn_width);
80 let v_vpn_split = valueOf(vpn_split);
81 let v_ppn_width = valueOf(ppn_width);
82 let v_real_ppn_width = valueOf(real_ppn_width);
83 let v_asid_width = valueOf(asid_width);
84 let v_levels = valueOf(levels);
85 let v_sub_levels = valueOf(sub_levels);
86 let v_addressable_bits = valueOf(addressable_bits);
87
88 function Tuple2#(Bool, Bit#(ppn_perm)) fn_super_page_physical_address(Bit#(vpn_width) vpn,
89 Bit#(data_width) pte,
90 Int#(32) levels);
91 Bool page_fault = !unpack(pte[0]);
92 Bit#(ppn_width) step_ppn = 0;
93 if(levels==3) begin
94 Bit#(TMul#(3,vpn_split)) offset_3 = pte[3*v_vpn_split+9:10];
95 Bit#(TSub#(ppn_width,TMul#(3,vpn_split))) ppn= pte[v_ppn_width+9:3*v_vpn_split+10];
96 Bit#(TMul#(3,vpn_split)) vpn_offset = vpn[3*v_vpn_split-1:0];
97 step_ppn = {ppn,vpn_offset};
98 if(offset_3!=0)
99 page_fault = True;
100 end
101 else if(levels==2) begin
102 Bit#(TMul#(2,vpn_split)) offset_2 = pte[2*v_vpn_split+9:10];
103 Bit#(TSub#(ppn_width,TMul#(2,vpn_split))) ppn= pte[v_ppn_width+9:2*v_vpn_split+10];
104 Bit#(TMul#(2,vpn_split)) vpn_offset = vpn[2*v_vpn_split-1:0];
105 step_ppn = {ppn,vpn_offset};
106 if(offset_2!=0)
107 page_fault = True;
108 end
109 else if(levels==1) begin
110 Bit#(TMul#(1,vpn_split)) offset_1 = pte[1*v_vpn_split+9:10];
111 Bit#(TSub#(ppn_width,TMul#(1,vpn_split))) ppn= pte[v_ppn_width+9:1*v_vpn_split+10];
112 Bit#(TMul#(1,vpn_split)) vpn_offset = vpn[1*v_vpn_split-1:0];
113 step_ppn = {ppn,vpn_offset};
114 if(offset_1!=0)
115 page_fault = True;
116 end
117 return tuple2(page_fault,{step_ppn,pte[9:0]});
118 endfunction
119
120 Reg#(Bit#(vpn_width)) rg_vpn <- mkReg(0);
121 Reg#(Int#(32)) rg_levels <- mkConfigReg(fromInteger(v_sub_levels));
122 Reg#(Bit#(data_width)) rg_ppn[2] <- mkCReg(2,0);
123 Reg#(Bit#(asid_width)) rg_asid[2] <- mkCReg(2,0);
124 Reg#(Bit#(data_width)) rg_pte <- mkReg(0);
125 Reg#(Bit#(data_width)) rg_pte_pointer <- mkReg(0);
126 Reg#(PTW_state) rg_ptw_state[2] <- mkCReg(2,PTW_ready);
127 Reg#(Bit#(data_width)) rg_satp <- mkReg(0);
128 Reg#(Bool) rg_page_fault <- mkReg(False);
129 Reg#(Bit#(10)) rg_permission_bits <- mkReg(0);
130 Reg#(Translation_type) rg_page_type <- mkConfigReg(Load);
131 Wire#(Bool) wr_flush <- mkDWire(False);
132
133 //(*conflict_free="rl_computer_next_pointer, rl_return_from_page_fault"*)
134 rule rl_computer_next_pointer(rg_ptw_state[1] == Handling_PTW && !wr_flush);
135 Int#(32) vpn_trnct = (rg_levels+1)*fromInteger(v_vpn_split);
136 Bit#(vpn_split) lv_vpn_split = rg_vpn[vpn_trnct-1:vpn_trnct-fromInteger(v_vpn_split)];
137 Bit#(page_size_bits) vpn_addr = zeroExtend(lv_vpn_split);
138 vpn_addr = vpn_addr << v_addressable_bits;
139 `ifdef verbose $display($time, "\tPTW: The VPN split bits are %d split is %h", vpn_trnct, vpn_addr); `endif
140 Int#(32) ppn_trnct = (rg_levels)*fromInteger(v_vpn_split) + 10;
141 Bit#(ppn_width) p_pte= rg_pte[v_ppn_width+9:10];
142 Bit#(data_width) lv_zeros = 0;
143 rg_permission_bits <= rg_pte[9:0];
144 `ifdef verbose $display($time, "\tPTW: page table entry %h and page level is %d", rg_pte, rg_levels); `endif
145 if(rg_pte[0]==0 || (rg_pte[1]==0 && rg_pte[2]==1)) begin
146 rg_ptw_state[1] <= PTW_done;
147 `ifdef verbose $display($time,"\tPTW: Page Fault due to reason1 "); `endif
148 rg_page_fault <= True;
149 end
150 else if((rg_pte[3]==1 || rg_pte[1]==1)) begin //if executable and read permission bits are 1 then it is a super page
151 rg_ptw_state[1] <= PTW_done;
152 match{.x,.y} = fn_super_page_physical_address(rg_vpn,rg_pte,rg_levels+1);
153 if(x) begin
154 rg_page_fault <= True;
155 `ifdef verbose $display($time,"Page Fault due to reason2 "); `endif
156 end
157 else begin
158 rg_pte <= zeroExtend(y);
159 `ifdef verbose $display($time,"Superpage has been found"); `endif
160 if(rg_pte[6]==0 || (rg_page_type==Store && rg_pte[7]==0))
161 rg_page_fault <= True;
162 end
163 //if(rg_pte[ppn_trnct-1:10]!=0) begin TODO
164 //Bit#(data_width) pte_paddr = rg_pte << ppn_trnct;
165 //Bit#(vpn_width) pte_vpn = rg_vpn << rg_levels*(fromInteger(v_vpn_split));
166 //Bit#(data_width) pte_vaddr = zeroExtend(pte_vpn);
167 //pte_vaddr = pte_vaddr >> rg_levels*fromInteger(v_vpn_split);
168 //rg_pte_pointer <= pte_paddr | pte_vaddr;
169 //`ifdef verbose $display($time, "\t It's is a superpage %h", pte_paddr | pte_vaddr); `endif
170 //end
171 //else
172 // rg_page_fault <= True;
173 end
174 else begin/* if(rg_levels == 0) begin
175 rg_ptw_state[1] <= Wait_for_memory;
176 rg_pte_pointer <= {rg_pte[v_data_width-1:10],lv_zeros[9:0]};
177 `ifdef verbose
178 Bit#(data_width) pte_pointer = {rg_pte[v_data_width-1:10],lv_zeros[9:0]};
179 $display($time, "\t %h", pte_pointer); `endif
180 end
181 else if(rg_levels != 0) begin*/
182 Bit#(paddr_width) lv_pte_pointer = {p_pte,vpn_addr};
183 rg_pte_pointer <= zeroExtend(lv_pte_pointer);
184 rg_ptw_state[1] <= Send_to_memory;
185 `ifdef verbose $display($time, "\t next page table pointer %h", lv_pte_pointer); `endif
186 end
187
188 endrule
189
190 rule rl_return_from_page_fault(wr_flush);
191 `ifdef verbose $display($time, "\tPTW: Flushed page table walk"); `endif
192 rg_ptw_state[1] <= PTW_ready;
193 rg_page_fault <= False;
194 rg_levels <= fromInteger(v_sub_levels);
195 endrule
196
197 interface frm_TLB = interface Put
198 method Action put(Request_PPN_PTW#(vaddr_width,page_size_bits) req) if(rg_ptw_state[1]==PTW_ready && !wr_flush);
199 rg_vpn <= req.vpn;
200 rg_page_type <= req.page_type;
201 `ifdef verbose $display($time, "\tPTW: vpn obtained is %h", req.vpn); `endif
202 rg_ptw_state[1] <= Handling_PTW;
203 endmethod
204 endinterface;
205
206 interface to_TLB = interface Get
207 method ActionValue#(Tuple2#(Bool,To_TLB#(real_paddr, page_size_bits, asid_width))) get if(rg_ptw_state[1]==PTW_done && !wr_flush);
208 rg_page_fault <= False;
209 rg_ptw_state[1] <= PTW_ready;
210 Bit#(2) pg_levels = truncate(pack(rg_levels) + 1);
211 rg_levels <= fromInteger(v_sub_levels);
212 if(rg_levels==fromInteger(v_sub_levels))
213 pg_levels=0;
214 `ifdef verbose $display($time, "\tPTW: physical page number %h with permission bits %b", rg_pte, rg_page_fault); `endif
215 return tuple2(rg_page_fault, To_TLB { ppn : rg_pte[v_real_ppn_width+9:10],
216 tlb_perm : ptw_to_tlb_perms(rg_pte[9:0]),
217 asid : rg_asid[1],
218 levels : pg_levels});
219 endmethod
220 endinterface;
221
222 interface ifc_memory = interface Ifc_memory
223 method ActionValue#(Request_PTE_memory#(data_width)) send_PTE_pointer if(!wr_flush && rg_ptw_state[1]== Send_to_memory);
224 `ifdef verbose $display($time, "\tPTW: Sending from PTW to dcache for address %h", rg_pte_pointer); `endif
225 rg_ptw_state[1] <= Wait_for_memory;
226 return Request_PTE_memory{ptwdone : (rg_ptw_state[1]==PTW_done), address : rg_pte_pointer, page_type : rg_page_type};
227 endmethod
228 method Action get_PTE(Bit#(data_width) pte) if(rg_ptw_state[1]== Wait_for_memory && !wr_flush);
229 `ifdef verbose $display($time, "\tPTW: pte obtained from memory %h", pte); `endif
230 rg_pte <= pte;
231 if(rg_levels == 0) begin
232 `ifdef verbose $display($time, "\tPTW: Last level PTW with pte %h and page fault", pte, rg_page_fault); `endif
233 rg_ptw_state[1] <= PTW_done;
234 if(pte[0]==0 || pte[6]==0 || (rg_page_type==Store && pte[7]==0)) begin
235 `ifdef verbose $display($time, "\tPTW: Access and dirty page fault %h", pte); `endif
236 rg_page_fault <= True;
237 end
238 rg_levels <= fromInteger(v_sub_levels);
239 end
240 else begin
241 rg_ptw_state[1] <= Handling_PTW;
242 rg_levels <= rg_levels-1;
243 end
244 endmethod
245 endinterface;
246
247 method Action satp_frm_csr(Bit#(data_width) satp) if(rg_ptw_state[1] == PTW_ready);
248 Bit#(ppn_width) p_pte = satp[v_ppn_width-1:0];
249 //Bit#(data_width) pte = zeroExtend(p_pte);
250 Bit#(10) perm_bits = 'b1;
251 Bit#(ppn_perm) pte ={p_pte,perm_bits};
252 rg_pte <= zeroExtend(pte);
253 //`ifdef verbose $display($time, "\t page table pointer %h", p_pte); `endif
254 rg_asid[0] <= satp[v_asid_width+v_ppn_width-1:v_ppn_width];
255 endmethod
256
257 method Action flush(Translation_type _flush);
258 if((rg_page_type==Execution && _flush==Execution) || (rg_page_type!=Execution && _flush!=Execution))
259 wr_flush <= True;
260 endmethod
261
262 //method Bool ptwalkdone;
263 // Bool done = False;
264 // if(rg_ptw_state[1]==PTW_done)
265 // done = True;
266 // return done;
267 //endmethod
268
269 //method Maybe#(Translation_type) page_fault /*if(rg_ptw_state[1]==PTW_done)*/;
270 // if(rg_page_fault)
271 // return tagged Valid rg_page_type;
272 // else
273 // return tagged Invalid;
274 //endmethod
275
276 endmodule
277 endpackage