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 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
17 import defined_types::*;
21 function TLB_permissions ptw_to_tlb_perms(Bit#(10) perms);
22 return TLB_permissions { v : perms[0],
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;
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);
42 interface Ifc_PTWalk#(numeric type data_width,
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;
57 module mkPTWalk(Ifc_PTWalk#(data_width,vaddr_width,paddr_width, real_paddr, asid_width,page_size_bits))
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)
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);
88 function Tuple2#(Bool, Bit#(ppn_perm)) fn_super_page_physical_address(Bit#(vpn_width) vpn,
91 Bool page_fault = !unpack(pte[0]);
92 Bit#(ppn_width) step_ppn = 0;
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};
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};
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};
117 return tuple2(page_fault,{step_ppn,pte[9:0]});
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);
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;
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);
154 rg_page_fault <= True;
155 `ifdef verbose $display($time,"Page Fault due to reason2 "); `endif
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;
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
172 // rg_page_fault <= True;
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]};
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
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
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);
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);
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;
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))
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]),
218 levels : pg_levels});
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};
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
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;
238 rg_levels <= fromInteger(v_sub_levels);
241 rg_ptw_state[1] <= Handling_PTW;
242 rg_levels <= rg_levels-1;
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];
257 method Action flush(Translation_type _flush);
258 if((rg_page_type==Execution && _flush==Execution) || (rg_page_type!=Execution && _flush!=Execution))
262 //method Bool ptwalkdone;
263 // Bool done = False;
264 // if(rg_ptw_state[1]==PTW_done)
269 //method Maybe#(Translation_type) page_fault /*if(rg_ptw_state[1]==PTW_done)*/;
271 // return tagged Valid rg_page_type;
273 // return tagged Invalid;