tlb.cc (8573:be51bef13962) tlb.cc (8575:02332ce6d7da)
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Nathan Binkert
30 * Steve Reinhardt
31 * Jaidev Patwardhan
32 */
33
34#include <string>
35#include <vector>
36
37#include "arch/mips/faults.hh"
38#include "arch/mips/pagetable.hh"
39#include "arch/mips/pra_constants.hh"
40#include "arch/mips/tlb.hh"
41#include "arch/mips/utility.hh"
42#include "base/inifile.hh"
43#include "base/str.hh"
44#include "base/trace.hh"
45#include "cpu/thread_context.hh"
46#include "debug/MipsPRA.hh"
47#include "debug/TLB.hh"
48#include "mem/page_table.hh"
49#include "params/MipsTLB.hh"
50#include "sim/process.hh"
51
52using namespace std;
53using namespace MipsISA;
54
55///////////////////////////////////////////////////////////////////////
56//
57// MIPS TLB
58//
59
60static inline mode_type
61getOperatingMode(MiscReg Stat)
62{
63 if ((Stat & 0x10000006) != 0 || (Stat & 0x18) ==0) {
64 return mode_kernel;
65 } else if ((Stat & 0x18) == 0x8) {
66 return mode_supervisor;
67 } else if ((Stat & 0x18) == 0x10) {
68 return mode_user;
69 } else {
70 return mode_number;
71 }
72}
73
74
75TLB::TLB(const Params *p)
76 : BaseTLB(p), size(p->size), nlu(0)
77{
78 table = new PTE[size];
79 memset(table, 0, sizeof(PTE[size]));
80 smallPages = 0;
81}
82
83TLB::~TLB()
84{
85 if (table)
86 delete [] table;
87}
88
89// look up an entry in the TLB
90MipsISA::PTE *
91TLB::lookup(Addr vpn, uint8_t asn) const
92{
93 // assume not found...
94 PTE *retval = NULL;
95 PageTable::const_iterator i = lookupTable.find(vpn);
96 if (i != lookupTable.end()) {
97 while (i->first == vpn) {
98 int index = i->second;
99 PTE *pte = &table[index];
100
101 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
102 Addr Mask = pte->Mask;
103 Addr InvMask = ~Mask;
104 Addr VPN = pte->VPN;
105 if (((vpn & InvMask) == (VPN & InvMask)) &&
106 (pte->G || (asn == pte->asid))) {
107 // We have a VPN + ASID Match
108 retval = pte;
109 break;
110 }
111 ++i;
112 }
113 }
114
115 DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
116 retval ? "hit" : "miss", retval ? retval->PFN1 : 0);
117 return retval;
118}
119
120MipsISA::PTE*
121TLB::getEntry(unsigned Index) const
122{
123 // Make sure that Index is valid
124 assert(Index<size);
125 return &table[Index];
126}
127
128int
129TLB::probeEntry(Addr vpn, uint8_t asn) const
130{
131 // assume not found...
132 PTE *retval = NULL;
133 int Ind = -1;
134 PageTable::const_iterator i = lookupTable.find(vpn);
135 if (i != lookupTable.end()) {
136 while (i->first == vpn) {
137 int index = i->second;
138 PTE *pte = &table[index];
139
140 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
141 Addr Mask = pte->Mask;
142 Addr InvMask = ~Mask;
143 Addr VPN = pte->VPN;
144 if (((vpn & InvMask) == (VPN & InvMask)) &&
145 (pte->G || (asn == pte->asid))) {
146 // We have a VPN + ASID Match
147 retval = pte;
148 Ind = index;
149 break;
150 }
151 ++i;
152 }
153 }
154 DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind);
155 return Ind;
156}
157
158inline Fault
159TLB::checkCacheability(RequestPtr &req)
160{
161 Addr VAddrUncacheable = 0xA0000000;
162 // In MIPS, cacheability is controlled by certain bits of the virtual
163 // address or by the TLB entry
164 if ((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
165 // mark request as uncacheable
166 req->setFlags(Request::UNCACHEABLE);
167 }
168 return NoFault;
169}
170
171void
172TLB::insertAt(PTE &pte, unsigned Index, int _smallPages)
173{
174 smallPages = _smallPages;
175 if (Index > size) {
176 warn("Attempted to write at index (%d) beyond TLB size (%d)",
177 Index, size);
178 } else {
179 // Update TLB
180 DPRINTF(TLB, "TLB[%d]: %x %x %x %x\n",
181 Index, pte.Mask << 11,
182 ((pte.VPN << 11) | pte.asid),
183 ((pte.PFN0 << 6) | (pte.C0 << 3) |
184 (pte.D0 << 2) | (pte.V0 <<1) | pte.G),
185 ((pte.PFN1 <<6) | (pte.C1 << 3) |
186 (pte.D1 << 2) | (pte.V1 <<1) | pte.G));
187 if (table[Index].V0 == true || table[Index].V1 == true) {
188 // Previous entry is valid
189 PageTable::iterator i = lookupTable.find(table[Index].VPN);
190 lookupTable.erase(i);
191 }
192 table[Index]=pte;
193 // Update fast lookup table
194 lookupTable.insert(make_pair(table[Index].VPN, Index));
195 }
196}
197
198// insert a new TLB entry
199void
200TLB::insert(Addr addr, PTE &pte)
201{
202 fatal("TLB Insert not yet implemented\n");
203}
204
205void
206TLB::flushAll()
207{
208 DPRINTF(TLB, "flushAll\n");
209 memset(table, 0, sizeof(PTE[size]));
210 lookupTable.clear();
211 nlu = 0;
212}
213
214void
215TLB::serialize(ostream &os)
216{
217 SERIALIZE_SCALAR(size);
218 SERIALIZE_SCALAR(nlu);
219
220 for (int i = 0; i < size; i++) {
221 nameOut(os, csprintf("%s.PTE%d", name(), i));
222 table[i].serialize(os);
223 }
224}
225
226void
227TLB::unserialize(Checkpoint *cp, const string &section)
228{
229 UNSERIALIZE_SCALAR(size);
230 UNSERIALIZE_SCALAR(nlu);
231
232 for (int i = 0; i < size; i++) {
233 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
234 if (table[i].V0 || table[i].V1) {
235 lookupTable.insert(make_pair(table[i].VPN, i));
236 }
237 }
238}
239
240void
241TLB::regStats()
242{
243 read_hits
244 .name(name() + ".read_hits")
245 .desc("DTB read hits")
246 ;
247
248 read_misses
249 .name(name() + ".read_misses")
250 .desc("DTB read misses")
251 ;
252
253
254 read_accesses
255 .name(name() + ".read_accesses")
256 .desc("DTB read accesses")
257 ;
258
259 write_hits
260 .name(name() + ".write_hits")
261 .desc("DTB write hits")
262 ;
263
264 write_misses
265 .name(name() + ".write_misses")
266 .desc("DTB write misses")
267 ;
268
269
270 write_accesses
271 .name(name() + ".write_accesses")
272 .desc("DTB write accesses")
273 ;
274
275 hits
276 .name(name() + ".hits")
277 .desc("DTB hits")
278 ;
279
280 misses
281 .name(name() + ".misses")
282 .desc("DTB misses")
283 ;
284
285 accesses
286 .name(name() + ".accesses")
287 .desc("DTB accesses")
288 ;
289
290 hits = read_hits + write_hits;
291 misses = read_misses + write_misses;
292 accesses = read_accesses + write_accesses;
293}
294
295Fault
296TLB::translateInst(RequestPtr req, ThreadContext *tc)
297{
298#if !FULL_SYSTEM
299 Process * p = tc->getProcessPtr();
300
301 Fault fault = p->pTable->translate(req);
302 if (fault != NoFault)
303 return fault;
304
305 return NoFault;
306#else
307 Addr vaddr = req->getVaddr();
308
309 bool misaligned = (req->getSize() - 1) & vaddr;
310
311 if (IsKSeg0(vaddr)) {
312 // Address will not be translated through TLB, set response, and go!
313 req->setPaddr(KSeg02Phys(vaddr));
314 if (getOperatingMode(tc->readMiscReg(MISCREG_STATUS)) != mode_kernel ||
315 misaligned) {
316 return new AddressErrorFault(vaddr, false);
317 }
318 } else if(IsKSeg1(vaddr)) {
319 // Address will not be translated through TLB, set response, and go!
320 req->setPaddr(KSeg02Phys(vaddr));
321 } else {
322 /*
323 * This is an optimization - smallPages is updated every time a TLB
324 * operation is performed. That way, we don't need to look at
325 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup
326 */
327 Addr VPN;
328 if (smallPages == 1) {
329 VPN = (vaddr >> 11);
330 } else {
331 VPN = ((vaddr >> 11) & 0xFFFFFFFC);
332 }
333 uint8_t Asid = req->getAsid();
334 if (misaligned) {
335 // Unaligned address!
336 return new AddressErrorFault(vaddr, false);
337 }
338 PTE *pte = lookup(VPN,Asid);
339 if (pte != NULL) {
340 // Ok, found something
341 /* Check for valid bits */
342 int EvenOdd;
343 bool Valid;
344 if ((((vaddr) >> pte->AddrShiftAmount) & 1) == 0) {
345 // Check even bits
346 Valid = pte->V0;
347 EvenOdd = 0;
348 } else {
349 // Check odd bits
350 Valid = pte->V1;
351 EvenOdd = 1;
352 }
353
354 if (Valid == false) {
355 return new InvalidFault(Asid, vaddr, vpn, false);
356 } else {
357 // Ok, this is really a match, set paddr
358 Addr PAddr;
359 if (EvenOdd == 0) {
360 PAddr = pte->PFN0;
361 } else {
362 PAddr = pte->PFN1;
363 }
364 PAddr >>= (pte->AddrShiftAmount - 12);
365 PAddr <<= pte->AddrShiftAmount;
366 PAddr |= (vaddr & pte->OffsetMask);
367 req->setPaddr(PAddr);
368 }
369 } else {
370 // Didn't find any match, return a TLB Refill Exception
371 return new RefillFault(Asid, vaddr, vpn, false);
372 }
373 }
374 return checkCacheability(req);
375#endif
376}
377
378Fault
379TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
380{
381#if !FULL_SYSTEM
382 //@TODO: This should actually use TLB instead of going directly
383 // to the page table in syscall mode.
384 /**
385 * Check for alignment faults
386 */
387 if (req->getVaddr() & (req->getSize() - 1)) {
388 DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
389 req->getSize());
390 return new AddressErrorFault(req->getVaddr(), write);
391 }
392
393
394 Process * p = tc->getProcessPtr();
395
396 Fault fault = p->pTable->translate(req);
397 if (fault != NoFault)
398 return fault;
399
400 return NoFault;
401#else
402 Addr vaddr = req->getVaddr();
403
404 bool misaligned = (req->getSize() - 1) & vaddr;
405
406 if (IsKSeg0(vaddr)) {
407 // Address will not be translated through TLB, set response, and go!
408 req->setPaddr(KSeg02Phys(vaddr));
409 if (getOperatingMode(tc->readMiscReg(MISCREG_STATUS)) != mode_kernel ||
410 misaligned) {
411 return new AddressErrorFault(vaddr, true);
412 }
413 } else if(IsKSeg1(vaddr)) {
414 // Address will not be translated through TLB, set response, and go!
415 req->setPaddr(KSeg02Phys(vaddr));
416 } else {
417 /*
418 * This is an optimization - smallPages is updated every time a TLB
419 * operation is performed. That way, we don't need to look at
420 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup
421 */
422 Addr VPN = (vaddr >> 11) & 0xFFFFFFFC;
423 if (smallPages == 1) {
424 VPN = vaddr >> 11;
425 }
426 uint8_t Asid = req->getAsid();
427 PTE *pte = lookup(VPN, Asid);
428 if (misaligned) {
429 return new AddressErrorFault(vaddr, true);
430 }
431 if (pte != NULL) {
432 // Ok, found something
433 /* Check for valid bits */
434 int EvenOdd;
435 bool Valid;
436 bool Dirty;
437 if ((((vaddr >> pte->AddrShiftAmount) & 1)) == 0) {
438 // Check even bits
439 Valid = pte->V0;
440 Dirty = pte->D0;
441 EvenOdd = 0;
442 } else {
443 // Check odd bits
444 Valid = pte->V1;
445 Dirty = pte->D1;
446 EvenOdd = 1;
447 }
448
449 if (Valid == false) {
450 return new InvalidFault(Asid, vaddr, VPN, true);
451 } else {
452 // Ok, this is really a match, set paddr
453 if (!Dirty) {
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Nathan Binkert
30 * Steve Reinhardt
31 * Jaidev Patwardhan
32 */
33
34#include <string>
35#include <vector>
36
37#include "arch/mips/faults.hh"
38#include "arch/mips/pagetable.hh"
39#include "arch/mips/pra_constants.hh"
40#include "arch/mips/tlb.hh"
41#include "arch/mips/utility.hh"
42#include "base/inifile.hh"
43#include "base/str.hh"
44#include "base/trace.hh"
45#include "cpu/thread_context.hh"
46#include "debug/MipsPRA.hh"
47#include "debug/TLB.hh"
48#include "mem/page_table.hh"
49#include "params/MipsTLB.hh"
50#include "sim/process.hh"
51
52using namespace std;
53using namespace MipsISA;
54
55///////////////////////////////////////////////////////////////////////
56//
57// MIPS TLB
58//
59
60static inline mode_type
61getOperatingMode(MiscReg Stat)
62{
63 if ((Stat & 0x10000006) != 0 || (Stat & 0x18) ==0) {
64 return mode_kernel;
65 } else if ((Stat & 0x18) == 0x8) {
66 return mode_supervisor;
67 } else if ((Stat & 0x18) == 0x10) {
68 return mode_user;
69 } else {
70 return mode_number;
71 }
72}
73
74
75TLB::TLB(const Params *p)
76 : BaseTLB(p), size(p->size), nlu(0)
77{
78 table = new PTE[size];
79 memset(table, 0, sizeof(PTE[size]));
80 smallPages = 0;
81}
82
83TLB::~TLB()
84{
85 if (table)
86 delete [] table;
87}
88
89// look up an entry in the TLB
90MipsISA::PTE *
91TLB::lookup(Addr vpn, uint8_t asn) const
92{
93 // assume not found...
94 PTE *retval = NULL;
95 PageTable::const_iterator i = lookupTable.find(vpn);
96 if (i != lookupTable.end()) {
97 while (i->first == vpn) {
98 int index = i->second;
99 PTE *pte = &table[index];
100
101 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
102 Addr Mask = pte->Mask;
103 Addr InvMask = ~Mask;
104 Addr VPN = pte->VPN;
105 if (((vpn & InvMask) == (VPN & InvMask)) &&
106 (pte->G || (asn == pte->asid))) {
107 // We have a VPN + ASID Match
108 retval = pte;
109 break;
110 }
111 ++i;
112 }
113 }
114
115 DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
116 retval ? "hit" : "miss", retval ? retval->PFN1 : 0);
117 return retval;
118}
119
120MipsISA::PTE*
121TLB::getEntry(unsigned Index) const
122{
123 // Make sure that Index is valid
124 assert(Index<size);
125 return &table[Index];
126}
127
128int
129TLB::probeEntry(Addr vpn, uint8_t asn) const
130{
131 // assume not found...
132 PTE *retval = NULL;
133 int Ind = -1;
134 PageTable::const_iterator i = lookupTable.find(vpn);
135 if (i != lookupTable.end()) {
136 while (i->first == vpn) {
137 int index = i->second;
138 PTE *pte = &table[index];
139
140 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
141 Addr Mask = pte->Mask;
142 Addr InvMask = ~Mask;
143 Addr VPN = pte->VPN;
144 if (((vpn & InvMask) == (VPN & InvMask)) &&
145 (pte->G || (asn == pte->asid))) {
146 // We have a VPN + ASID Match
147 retval = pte;
148 Ind = index;
149 break;
150 }
151 ++i;
152 }
153 }
154 DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind);
155 return Ind;
156}
157
158inline Fault
159TLB::checkCacheability(RequestPtr &req)
160{
161 Addr VAddrUncacheable = 0xA0000000;
162 // In MIPS, cacheability is controlled by certain bits of the virtual
163 // address or by the TLB entry
164 if ((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
165 // mark request as uncacheable
166 req->setFlags(Request::UNCACHEABLE);
167 }
168 return NoFault;
169}
170
171void
172TLB::insertAt(PTE &pte, unsigned Index, int _smallPages)
173{
174 smallPages = _smallPages;
175 if (Index > size) {
176 warn("Attempted to write at index (%d) beyond TLB size (%d)",
177 Index, size);
178 } else {
179 // Update TLB
180 DPRINTF(TLB, "TLB[%d]: %x %x %x %x\n",
181 Index, pte.Mask << 11,
182 ((pte.VPN << 11) | pte.asid),
183 ((pte.PFN0 << 6) | (pte.C0 << 3) |
184 (pte.D0 << 2) | (pte.V0 <<1) | pte.G),
185 ((pte.PFN1 <<6) | (pte.C1 << 3) |
186 (pte.D1 << 2) | (pte.V1 <<1) | pte.G));
187 if (table[Index].V0 == true || table[Index].V1 == true) {
188 // Previous entry is valid
189 PageTable::iterator i = lookupTable.find(table[Index].VPN);
190 lookupTable.erase(i);
191 }
192 table[Index]=pte;
193 // Update fast lookup table
194 lookupTable.insert(make_pair(table[Index].VPN, Index));
195 }
196}
197
198// insert a new TLB entry
199void
200TLB::insert(Addr addr, PTE &pte)
201{
202 fatal("TLB Insert not yet implemented\n");
203}
204
205void
206TLB::flushAll()
207{
208 DPRINTF(TLB, "flushAll\n");
209 memset(table, 0, sizeof(PTE[size]));
210 lookupTable.clear();
211 nlu = 0;
212}
213
214void
215TLB::serialize(ostream &os)
216{
217 SERIALIZE_SCALAR(size);
218 SERIALIZE_SCALAR(nlu);
219
220 for (int i = 0; i < size; i++) {
221 nameOut(os, csprintf("%s.PTE%d", name(), i));
222 table[i].serialize(os);
223 }
224}
225
226void
227TLB::unserialize(Checkpoint *cp, const string &section)
228{
229 UNSERIALIZE_SCALAR(size);
230 UNSERIALIZE_SCALAR(nlu);
231
232 for (int i = 0; i < size; i++) {
233 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
234 if (table[i].V0 || table[i].V1) {
235 lookupTable.insert(make_pair(table[i].VPN, i));
236 }
237 }
238}
239
240void
241TLB::regStats()
242{
243 read_hits
244 .name(name() + ".read_hits")
245 .desc("DTB read hits")
246 ;
247
248 read_misses
249 .name(name() + ".read_misses")
250 .desc("DTB read misses")
251 ;
252
253
254 read_accesses
255 .name(name() + ".read_accesses")
256 .desc("DTB read accesses")
257 ;
258
259 write_hits
260 .name(name() + ".write_hits")
261 .desc("DTB write hits")
262 ;
263
264 write_misses
265 .name(name() + ".write_misses")
266 .desc("DTB write misses")
267 ;
268
269
270 write_accesses
271 .name(name() + ".write_accesses")
272 .desc("DTB write accesses")
273 ;
274
275 hits
276 .name(name() + ".hits")
277 .desc("DTB hits")
278 ;
279
280 misses
281 .name(name() + ".misses")
282 .desc("DTB misses")
283 ;
284
285 accesses
286 .name(name() + ".accesses")
287 .desc("DTB accesses")
288 ;
289
290 hits = read_hits + write_hits;
291 misses = read_misses + write_misses;
292 accesses = read_accesses + write_accesses;
293}
294
295Fault
296TLB::translateInst(RequestPtr req, ThreadContext *tc)
297{
298#if !FULL_SYSTEM
299 Process * p = tc->getProcessPtr();
300
301 Fault fault = p->pTable->translate(req);
302 if (fault != NoFault)
303 return fault;
304
305 return NoFault;
306#else
307 Addr vaddr = req->getVaddr();
308
309 bool misaligned = (req->getSize() - 1) & vaddr;
310
311 if (IsKSeg0(vaddr)) {
312 // Address will not be translated through TLB, set response, and go!
313 req->setPaddr(KSeg02Phys(vaddr));
314 if (getOperatingMode(tc->readMiscReg(MISCREG_STATUS)) != mode_kernel ||
315 misaligned) {
316 return new AddressErrorFault(vaddr, false);
317 }
318 } else if(IsKSeg1(vaddr)) {
319 // Address will not be translated through TLB, set response, and go!
320 req->setPaddr(KSeg02Phys(vaddr));
321 } else {
322 /*
323 * This is an optimization - smallPages is updated every time a TLB
324 * operation is performed. That way, we don't need to look at
325 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup
326 */
327 Addr VPN;
328 if (smallPages == 1) {
329 VPN = (vaddr >> 11);
330 } else {
331 VPN = ((vaddr >> 11) & 0xFFFFFFFC);
332 }
333 uint8_t Asid = req->getAsid();
334 if (misaligned) {
335 // Unaligned address!
336 return new AddressErrorFault(vaddr, false);
337 }
338 PTE *pte = lookup(VPN,Asid);
339 if (pte != NULL) {
340 // Ok, found something
341 /* Check for valid bits */
342 int EvenOdd;
343 bool Valid;
344 if ((((vaddr) >> pte->AddrShiftAmount) & 1) == 0) {
345 // Check even bits
346 Valid = pte->V0;
347 EvenOdd = 0;
348 } else {
349 // Check odd bits
350 Valid = pte->V1;
351 EvenOdd = 1;
352 }
353
354 if (Valid == false) {
355 return new InvalidFault(Asid, vaddr, vpn, false);
356 } else {
357 // Ok, this is really a match, set paddr
358 Addr PAddr;
359 if (EvenOdd == 0) {
360 PAddr = pte->PFN0;
361 } else {
362 PAddr = pte->PFN1;
363 }
364 PAddr >>= (pte->AddrShiftAmount - 12);
365 PAddr <<= pte->AddrShiftAmount;
366 PAddr |= (vaddr & pte->OffsetMask);
367 req->setPaddr(PAddr);
368 }
369 } else {
370 // Didn't find any match, return a TLB Refill Exception
371 return new RefillFault(Asid, vaddr, vpn, false);
372 }
373 }
374 return checkCacheability(req);
375#endif
376}
377
378Fault
379TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
380{
381#if !FULL_SYSTEM
382 //@TODO: This should actually use TLB instead of going directly
383 // to the page table in syscall mode.
384 /**
385 * Check for alignment faults
386 */
387 if (req->getVaddr() & (req->getSize() - 1)) {
388 DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
389 req->getSize());
390 return new AddressErrorFault(req->getVaddr(), write);
391 }
392
393
394 Process * p = tc->getProcessPtr();
395
396 Fault fault = p->pTable->translate(req);
397 if (fault != NoFault)
398 return fault;
399
400 return NoFault;
401#else
402 Addr vaddr = req->getVaddr();
403
404 bool misaligned = (req->getSize() - 1) & vaddr;
405
406 if (IsKSeg0(vaddr)) {
407 // Address will not be translated through TLB, set response, and go!
408 req->setPaddr(KSeg02Phys(vaddr));
409 if (getOperatingMode(tc->readMiscReg(MISCREG_STATUS)) != mode_kernel ||
410 misaligned) {
411 return new AddressErrorFault(vaddr, true);
412 }
413 } else if(IsKSeg1(vaddr)) {
414 // Address will not be translated through TLB, set response, and go!
415 req->setPaddr(KSeg02Phys(vaddr));
416 } else {
417 /*
418 * This is an optimization - smallPages is updated every time a TLB
419 * operation is performed. That way, we don't need to look at
420 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup
421 */
422 Addr VPN = (vaddr >> 11) & 0xFFFFFFFC;
423 if (smallPages == 1) {
424 VPN = vaddr >> 11;
425 }
426 uint8_t Asid = req->getAsid();
427 PTE *pte = lookup(VPN, Asid);
428 if (misaligned) {
429 return new AddressErrorFault(vaddr, true);
430 }
431 if (pte != NULL) {
432 // Ok, found something
433 /* Check for valid bits */
434 int EvenOdd;
435 bool Valid;
436 bool Dirty;
437 if ((((vaddr >> pte->AddrShiftAmount) & 1)) == 0) {
438 // Check even bits
439 Valid = pte->V0;
440 Dirty = pte->D0;
441 EvenOdd = 0;
442 } else {
443 // Check odd bits
444 Valid = pte->V1;
445 Dirty = pte->D1;
446 EvenOdd = 1;
447 }
448
449 if (Valid == false) {
450 return new InvalidFault(Asid, vaddr, VPN, true);
451 } else {
452 // Ok, this is really a match, set paddr
453 if (!Dirty) {
454 return new TLBModifiedFault(Asid, vaddr, VPN);
454 return new TlbModifiedFault(Asid, vaddr, VPN);
455 }
456 Addr PAddr;
457 if (EvenOdd == 0) {
458 PAddr = pte->PFN0;
459 } else {
460 PAddr = pte->PFN1;
461 }
462 PAddr >>= (pte->AddrShiftAmount - 12);
463 PAddr <<= pte->AddrShiftAmount;
464 PAddr |= (vaddr & pte->OffsetMask);
465 req->setPaddr(PAddr);
466 }
467 } else {
468 // Didn't find any match, return a TLB Refill Exception
469 return new RefillFault(Asid, vaddr, VPN, true);
470 }
471 }
472 return checkCacheability(req);
473#endif
474}
475
476Fault
477TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
478{
479 if (mode == Execute)
480 return translateInst(req, tc);
481 else
482 return translateData(req, tc, mode == Write);
483}
484
485void
486TLB::translateTiming(RequestPtr req, ThreadContext *tc,
487 Translation *translation, Mode mode)
488{
489 assert(translation);
490 translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
491}
492
493
494MipsISA::PTE &
495TLB::index(bool advance)
496{
497 PTE *pte = &table[nlu];
498
499 if (advance)
500 nextnlu();
501
502 return *pte;
503}
504
505MipsISA::TLB *
506MipsTLBParams::create()
507{
508 return new TLB(this);
509}
455 }
456 Addr PAddr;
457 if (EvenOdd == 0) {
458 PAddr = pte->PFN0;
459 } else {
460 PAddr = pte->PFN1;
461 }
462 PAddr >>= (pte->AddrShiftAmount - 12);
463 PAddr <<= pte->AddrShiftAmount;
464 PAddr |= (vaddr & pte->OffsetMask);
465 req->setPaddr(PAddr);
466 }
467 } else {
468 // Didn't find any match, return a TLB Refill Exception
469 return new RefillFault(Asid, vaddr, VPN, true);
470 }
471 }
472 return checkCacheability(req);
473#endif
474}
475
476Fault
477TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
478{
479 if (mode == Execute)
480 return translateInst(req, tc);
481 else
482 return translateData(req, tc, mode == Write);
483}
484
485void
486TLB::translateTiming(RequestPtr req, ThreadContext *tc,
487 Translation *translation, Mode mode)
488{
489 assert(translation);
490 translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
491}
492
493
494MipsISA::PTE &
495TLB::index(bool advance)
496{
497 PTE *pte = &table[nlu];
498
499 if (advance)
500 nextnlu();
501
502 return *pte;
503}
504
505MipsISA::TLB *
506MipsTLBParams::create()
507{
508 return new TLB(this);
509}