2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
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.
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.
29 * Authors: Nathan Binkert
37 #include "arch/mips/pra_constants.hh"
38 #include "arch/mips/pagetable.hh"
39 #include "arch/mips/tlb.hh"
40 #include "arch/mips/faults.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 "sim/process.hh"
47 #include "mem/page_table.hh"
48 #include "params/MipsTLB.hh"
52 using namespace MipsISA
;
54 ///////////////////////////////////////////////////////////////////////
59 static inline mode_type
60 getOperatingMode(MiscReg Stat
)
62 if ((Stat
& 0x10000006) != 0 || (Stat
& 0x18) ==0) {
64 } else if ((Stat
& 0x18) == 0x8) {
65 return mode_supervisor
;
66 } else if ((Stat
& 0x18) == 0x10) {
74 TLB::TLB(const Params
*p
)
75 : BaseTLB(p
), size(p
->size
), nlu(0)
77 table
= new PTE
[size
];
78 memset(table
, 0, sizeof(PTE
[size
]));
88 // look up an entry in the TLB
90 TLB::lookup(Addr vpn
, uint8_t asn
) const
92 // assume not found...
94 PageTable::const_iterator i
= lookupTable
.find(vpn
);
95 if (i
!= lookupTable
.end()) {
96 while (i
->first
== vpn
) {
97 int index
= i
->second
;
98 PTE
*pte
= &table
[index
];
100 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
101 Addr Mask
= pte
->Mask
;
102 Addr InvMask
= ~Mask
;
104 if (((vpn
& InvMask
) == (VPN
& InvMask
)) &&
105 (pte
->G
|| (asn
== pte
->asid
))) {
106 // We have a VPN + ASID Match
114 DPRINTF(TLB
, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn
, (int)asn
,
115 retval
? "hit" : "miss", retval
? retval
->PFN1
: 0);
120 TLB::getEntry(unsigned Index
) const
122 // Make sure that Index is valid
124 return &table
[Index
];
128 TLB::probeEntry(Addr vpn
, uint8_t asn
) const
130 // assume not found...
133 PageTable::const_iterator i
= lookupTable
.find(vpn
);
134 if (i
!= lookupTable
.end()) {
135 while (i
->first
== vpn
) {
136 int index
= i
->second
;
137 PTE
*pte
= &table
[index
];
139 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
140 Addr Mask
= pte
->Mask
;
141 Addr InvMask
= ~Mask
;
143 if (((vpn
& InvMask
) == (VPN
& InvMask
)) &&
144 (pte
->G
|| (asn
== pte
->asid
))) {
145 // We have a VPN + ASID Match
153 DPRINTF(MipsPRA
,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn
,asn
,Ind
);
158 TLB::checkCacheability(RequestPtr
&req
)
160 Addr VAddrUncacheable
= 0xA0000000;
161 // In MIPS, cacheability is controlled by certain bits of the virtual
162 // address or by the TLB entry
163 if ((req
->getVaddr() & VAddrUncacheable
) == VAddrUncacheable
) {
164 // mark request as uncacheable
165 req
->setFlags(Request::UNCACHEABLE
);
171 TLB::insertAt(PTE
&pte
, unsigned Index
, int _smallPages
)
173 smallPages
= _smallPages
;
175 warn("Attempted to write at index (%d) beyond TLB size (%d)",
179 DPRINTF(TLB
, "TLB[%d]: %x %x %x %x\n",
180 Index
, pte
.Mask
<< 11,
181 ((pte
.VPN
<< 11) | pte
.asid
),
182 ((pte
.PFN0
<< 6) | (pte
.C0
<< 3) |
183 (pte
.D0
<< 2) | (pte
.V0
<<1) | pte
.G
),
184 ((pte
.PFN1
<<6) | (pte
.C1
<< 3) |
185 (pte
.D1
<< 2) | (pte
.V1
<<1) | pte
.G
));
186 if (table
[Index
].V0
== true || table
[Index
].V1
== true) {
187 // Previous entry is valid
188 PageTable::iterator i
= lookupTable
.find(table
[Index
].VPN
);
189 lookupTable
.erase(i
);
192 // Update fast lookup table
193 lookupTable
.insert(make_pair(table
[Index
].VPN
, Index
));
197 // insert a new TLB entry
199 TLB::insert(Addr addr
, PTE
&pte
)
201 fatal("TLB Insert not yet implemented\n");
207 DPRINTF(TLB
, "flushAll\n");
208 memset(table
, 0, sizeof(PTE
[size
]));
214 TLB::serialize(ostream
&os
)
216 SERIALIZE_SCALAR(size
);
217 SERIALIZE_SCALAR(nlu
);
219 for (int i
= 0; i
< size
; i
++) {
220 nameOut(os
, csprintf("%s.PTE%d", name(), i
));
221 table
[i
].serialize(os
);
226 TLB::unserialize(Checkpoint
*cp
, const string
§ion
)
228 UNSERIALIZE_SCALAR(size
);
229 UNSERIALIZE_SCALAR(nlu
);
231 for (int i
= 0; i
< size
; i
++) {
232 table
[i
].unserialize(cp
, csprintf("%s.PTE%d", section
, i
));
233 if (table
[i
].V0
|| table
[i
].V1
) {
234 lookupTable
.insert(make_pair(table
[i
].VPN
, i
));
243 .name(name() + ".read_hits")
244 .desc("DTB read hits")
248 .name(name() + ".read_misses")
249 .desc("DTB read misses")
254 .name(name() + ".read_accesses")
255 .desc("DTB read accesses")
259 .name(name() + ".write_hits")
260 .desc("DTB write hits")
264 .name(name() + ".write_misses")
265 .desc("DTB write misses")
270 .name(name() + ".write_accesses")
271 .desc("DTB write accesses")
275 .name(name() + ".hits")
280 .name(name() + ".misses")
285 .name(name() + ".invalids")
286 .desc("DTB access violations")
290 .name(name() + ".accesses")
291 .desc("DTB accesses")
294 hits
= read_hits
+ write_hits
;
295 misses
= read_misses
+ write_misses
;
296 accesses
= read_accesses
+ write_accesses
;
300 TLB::translateInst(RequestPtr req
, ThreadContext
*tc
)
303 Process
* p
= tc
->getProcessPtr();
305 Fault fault
= p
->pTable
->translate(req
);
306 if (fault
!= NoFault
)
311 if (IsKSeg0(req
->getVaddr())) {
312 // Address will not be translated through TLB, set response, and go!
313 req
->setPaddr(KSeg02Phys(req
->getVaddr()));
314 if (getOperatingMode(tc
->readMiscReg(MISCREG_STATUS
)) != mode_kernel
||
315 req
->isMisaligned()) {
316 AddressErrorFault
*Flt
= new AddressErrorFault();
317 /* BadVAddr must be set */
318 Flt
->badVAddr
= req
->getVaddr();
321 } else if(IsKSeg1(req
->getVaddr())) {
322 // Address will not be translated through TLB, set response, and go!
323 req
->setPaddr(KSeg02Phys(req
->getVaddr()));
326 * This is an optimization - smallPages is updated every time a TLB
327 * operation is performed. That way, we don't need to look at
328 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup
331 if (smallPages
== 1) {
332 VPN
= ((req
->getVaddr() >> 11));
334 VPN
= ((req
->getVaddr() >> 11) & 0xFFFFFFFC);
336 uint8_t Asid
= req
->getAsid();
337 if (req
->isMisaligned()) {
338 // Unaligned address!
339 AddressErrorFault
*Flt
= new AddressErrorFault();
340 /* BadVAddr must be set */
341 Flt
->badVAddr
= req
->getVaddr();
344 PTE
*pte
= lookup(VPN
,Asid
);
346 // Ok, found something
347 /* Check for valid bits */
350 if ((((req
->getVaddr()) >> pte
->AddrShiftAmount
) & 1) == 0) {
360 if (Valid
== false) {
362 ItbInvalidFault
*Flt
= new ItbInvalidFault();
363 /* EntryHi VPN, ASID fields must be set */
364 Flt
->entryHiAsid
= Asid
;
365 Flt
->entryHiVPN2
= (VPN
>> 2);
366 Flt
->entryHiVPN2X
= (VPN
& 0x3);
368 /* BadVAddr must be set */
369 Flt
->badVAddr
= req
->getVaddr();
371 /* Context must be set */
372 Flt
->contextBadVPN2
= (VPN
>> 2);
375 // Ok, this is really a match, set paddr
382 PAddr
>>= (pte
->AddrShiftAmount
- 12);
383 PAddr
<<= pte
->AddrShiftAmount
;
384 PAddr
|= ((req
->getVaddr()) & pte
->OffsetMask
);
385 req
->setPaddr(PAddr
);
388 // Didn't find any match, return a TLB Refill Exception
389 ItbRefillFault
*Flt
= new ItbRefillFault();
390 /* EntryHi VPN, ASID fields must be set */
391 Flt
->entryHiAsid
= Asid
;
392 Flt
->entryHiVPN2
= (VPN
>> 2);
393 Flt
->entryHiVPN2X
= (VPN
& 0x3);
395 /* BadVAddr must be set */
396 Flt
->badVAddr
= req
->getVaddr();
398 /* Context must be set */
399 Flt
->contextBadVPN2
= (VPN
>> 2);
403 return checkCacheability(req
);
408 TLB::translateData(RequestPtr req
, ThreadContext
*tc
, bool write
)
411 //@TODO: This should actually use TLB instead of going directly
412 // to the page table in syscall mode.
414 * Check for alignment faults
416 if (req
->getVaddr() & (req
->getSize() - 1)) {
417 DPRINTF(TLB
, "Alignment Fault on %#x, size = %d", req
->getVaddr(),
419 return new AlignmentFault();
423 Process
* p
= tc
->getProcessPtr();
425 Fault fault
= p
->pTable
->translate(req
);
426 if (fault
!= NoFault
)
431 if (IsKSeg0(req
->getVaddr())) {
432 // Address will not be translated through TLB, set response, and go!
433 req
->setPaddr(KSeg02Phys(req
->getVaddr()));
434 if (getOperatingMode(tc
->readMiscReg(MISCREG_STATUS
)) != mode_kernel
||
435 req
->isMisaligned()) {
436 StoreAddressErrorFault
*Flt
= new StoreAddressErrorFault();
437 /* BadVAddr must be set */
438 Flt
->badVAddr
= req
->getVaddr();
442 } else if(IsKSeg1(req
->getVaddr())) {
443 // Address will not be translated through TLB, set response, and go!
444 req
->setPaddr(KSeg02Phys(req
->getVaddr()));
447 * This is an optimization - smallPages is updated every time a TLB
448 * operation is performed. That way, we don't need to look at
449 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup
451 Addr VPN
= ((req
->getVaddr() >> 11) & 0xFFFFFFFC);
452 if (smallPages
== 1) {
453 VPN
= ((req
->getVaddr() >> 11));
455 uint8_t Asid
= req
->getAsid();
456 PTE
*pte
= lookup(VPN
, Asid
);
457 if (req
->isMisaligned()) {
458 // Unaligned address!
459 StoreAddressErrorFault
*Flt
= new StoreAddressErrorFault();
460 /* BadVAddr must be set */
461 Flt
->badVAddr
= req
->getVaddr();
465 // Ok, found something
466 /* Check for valid bits */
470 if (((((req
->getVaddr()) >> pte
->AddrShiftAmount
) & 1)) == 0) {
482 if (Valid
== false) {
484 DtbInvalidFault
*Flt
= new DtbInvalidFault();
485 /* EntryHi VPN, ASID fields must be set */
486 Flt
->entryHiAsid
= Asid
;
487 Flt
->entryHiVPN2
= (VPN
>>2);
488 Flt
->entryHiVPN2X
= (VPN
& 0x3);
490 /* BadVAddr must be set */
491 Flt
->badVAddr
= req
->getVaddr();
493 /* Context must be set */
494 Flt
->contextBadVPN2
= (VPN
>> 2);
498 // Ok, this is really a match, set paddr
500 TLBModifiedFault
*Flt
= new TLBModifiedFault();
501 /* EntryHi VPN, ASID fields must be set */
502 Flt
->entryHiAsid
= Asid
;
503 Flt
->entryHiVPN2
= (VPN
>> 2);
504 Flt
->entryHiVPN2X
= (VPN
& 0x3);
506 /* BadVAddr must be set */
507 Flt
->badVAddr
= req
->getVaddr();
509 /* Context must be set */
510 Flt
->contextBadVPN2
= (VPN
>> 2);
519 PAddr
>>= (pte
->AddrShiftAmount
- 12);
520 PAddr
<<= pte
->AddrShiftAmount
;
521 PAddr
|= ((req
->getVaddr()) & pte
->OffsetMask
);
522 req
->setPaddr(PAddr
);
525 // Didn't find any match, return a TLB Refill Exception
526 DtbRefillFault
*Flt
= new DtbRefillFault();
527 /* EntryHi VPN, ASID fields must be set */
528 Flt
->entryHiAsid
= Asid
;
529 Flt
->entryHiVPN2
= (VPN
>> 2);
530 Flt
->entryHiVPN2X
= (VPN
& 0x3);
532 /* BadVAddr must be set */
533 Flt
->badVAddr
= req
->getVaddr();
535 /* Context must be set */
536 Flt
->contextBadVPN2
= (VPN
>> 2);
540 return checkCacheability(req
);
545 TLB::translateAtomic(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
548 return translateInst(req
, tc
);
550 return translateData(req
, tc
, mode
== Write
);
554 TLB::translateTiming(RequestPtr req
, ThreadContext
*tc
,
555 Translation
*translation
, Mode mode
)
558 translation
->finish(translateAtomic(req
, tc
, mode
), req
, tc
, mode
);
563 TLB::index(bool advance
)
565 PTE
*pte
= &table
[nlu
];
574 MipsTLBParams::create()
576 return new TLB(this);