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 #define MODE2MASK(X) (1 << (X))
61 static inline mode_type
62 getOperatingMode(MiscReg Stat
)
64 if((Stat
& 0x10000006) != 0 || (Stat
& 0x18) ==0) {
66 } else if((Stat
& 0x18) == 0x8) {
67 return mode_supervisor
;
68 } else if((Stat
& 0x18) == 0x10) {
76 TLB::TLB(const Params
*p
)
77 : BaseTLB(p
), size(p
->size
), nlu(0)
79 table
= new MipsISA::PTE
[size
];
80 memset(table
, 0, sizeof(MipsISA::PTE
[size
]));
90 // look up an entry in the TLB
92 TLB::lookup(Addr vpn
, uint8_t asn
) const
94 // assume not found...
95 MipsISA::PTE
*retval
= NULL
;
96 PageTable::const_iterator i
= lookupTable
.find(vpn
);
97 if (i
!= lookupTable
.end()) {
98 while (i
->first
== vpn
) {
99 int index
= i
->second
;
100 MipsISA::PTE
*pte
= &table
[index
];
102 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
103 Addr Mask
= pte
->Mask
;
104 Addr InvMask
= ~Mask
;
106 // warn("Valid: %d - %d\n",pte->V0,pte->V1);
107 if(((vpn
& InvMask
) == (VPN
& InvMask
)) && (pte
->G
|| (asn
== pte
->asid
)))
108 { // We have a VPN + ASID Match
116 DPRINTF(TLB
, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn
, (int)asn
,
117 retval
? "hit" : "miss", retval
? retval
->PFN1
: 0);
121 MipsISA::PTE
* TLB::getEntry(unsigned Index
) const
123 // Make sure that Index is valid
125 return &table
[Index
];
128 int TLB::probeEntry(Addr vpn
,uint8_t asn
) const
130 // assume not found...
131 MipsISA::PTE
*retval
= NULL
;
133 PageTable::const_iterator i
= lookupTable
.find(vpn
);
134 if (i
!= lookupTable
.end()) {
135 while (i
->first
== vpn
) {
136 int index
= i
->second
;
137 MipsISA::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
)) && (pte
->G
|| (asn
== pte
->asid
)))
144 { // We have a VPN + ASID Match
153 DPRINTF(MipsPRA
,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn
,asn
,Ind
);
157 TLB::checkCacheability(RequestPtr
&req
)
159 Addr VAddrUncacheable
= 0xA0000000;
160 // In MIPS, cacheability is controlled by certain bits of the virtual address
161 // or by the TLB entry
162 if((req
->getVaddr() & VAddrUncacheable
) == VAddrUncacheable
) {
163 // mark request as uncacheable
164 req
->setFlags(Request::UNCACHEABLE
);
168 void TLB::insertAt(MipsISA::PTE
&pte
, unsigned Index
, int _smallPages
)
170 smallPages
=_smallPages
;
172 warn("Attempted to write at index (%d) beyond TLB size (%d)",Index
,size
);
175 DPRINTF(TLB
,"TLB[%d]: %x %x %x %x\n",Index
,pte
.Mask
<<11,((pte
.VPN
<< 11) | pte
.asid
),((pte
.PFN0
<<6) | (pte
.C0
<< 3) | (pte
.D0
<< 2) | (pte
.V0
<<1) | pte
.G
),
176 ((pte
.PFN1
<<6) | (pte
.C1
<< 3) | (pte
.D1
<< 2) | (pte
.V1
<<1) | pte
.G
));
177 if(table
[Index
].V0
== true || table
[Index
].V1
== true){ // Previous entry is valid
178 PageTable::iterator i
= lookupTable
.find(table
[Index
].VPN
);
179 lookupTable
.erase(i
);
182 // Update fast lookup table
183 lookupTable
.insert(make_pair(table
[Index
].VPN
, Index
));
184 // int TestIndex=probeEntry(pte.VPN,pte.asid);
185 // warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask);
190 // insert a new TLB entry
192 TLB::insert(Addr addr
, MipsISA::PTE
&pte
)
194 fatal("TLB Insert not yet implemented\n");
197 /* MipsISA::VAddr vaddr = addr;
198 if (table[nlu].valid) {
199 Addr oldvpn = table[nlu].tag;
200 PageTable::iterator i = lookupTable.find(oldvpn);
202 if (i == lookupTable.end())
203 panic("TLB entry not found in lookupTable");
206 while ((index = i->second) != nlu) {
207 if (table[index].tag != oldvpn)
208 panic("TLB entry not found in lookupTable");
213 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
215 lookupTable.erase(i);
218 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
221 table[nlu].tag = vaddr.vpn();
222 table[nlu].valid = true;
224 lookupTable.insert(make_pair(vaddr.vpn(), nlu));
232 DPRINTF(TLB
, "flushAll\n");
233 memset(table
, 0, sizeof(MipsISA::PTE
[size
]));
239 TLB::serialize(ostream
&os
)
241 SERIALIZE_SCALAR(size
);
242 SERIALIZE_SCALAR(nlu
);
244 for (int i
= 0; i
< size
; i
++) {
245 nameOut(os
, csprintf("%s.PTE%d", name(), i
));
246 table
[i
].serialize(os
);
251 TLB::unserialize(Checkpoint
*cp
, const string
§ion
)
253 UNSERIALIZE_SCALAR(size
);
254 UNSERIALIZE_SCALAR(nlu
);
256 for (int i
= 0; i
< size
; i
++) {
257 table
[i
].unserialize(cp
, csprintf("%s.PTE%d", section
, i
));
258 if (table
[i
].V0
|| table
[i
].V1
) {
259 lookupTable
.insert(make_pair(table
[i
].VPN
, i
));
268 .name(name() + ".read_hits")
269 .desc("DTB read hits")
273 .name(name() + ".read_misses")
274 .desc("DTB read misses")
279 .name(name() + ".read_accesses")
280 .desc("DTB read accesses")
284 .name(name() + ".write_hits")
285 .desc("DTB write hits")
289 .name(name() + ".write_misses")
290 .desc("DTB write misses")
295 .name(name() + ".write_accesses")
296 .desc("DTB write accesses")
300 .name(name() + ".hits")
305 .name(name() + ".misses")
310 .name(name() + ".invalids")
311 .desc("DTB access violations")
315 .name(name() + ".accesses")
316 .desc("DTB accesses")
319 hits
= read_hits
+ write_hits
;
320 misses
= read_misses
+ write_misses
;
321 accesses
= read_accesses
+ write_accesses
;
325 TLB::translateInst(RequestPtr req
, ThreadContext
*tc
)
328 Process
* p
= tc
->getProcessPtr();
330 Fault fault
= p
->pTable
->translate(req
);
336 if(MipsISA::IsKSeg0(req
->getVaddr()))
338 // Address will not be translated through TLB, set response, and go!
339 req
->setPaddr(MipsISA::KSeg02Phys(req
->getVaddr()));
340 if(MipsISA::getOperatingMode(tc
->readMiscReg(MipsISA::Status
)) != mode_kernel
|| req
->isMisaligned())
342 AddressErrorFault
*Flt
= new AddressErrorFault();
343 /* BadVAddr must be set */
344 Flt
->BadVAddr
= req
->getVaddr();
348 else if(MipsISA::IsKSeg1(req
->getVaddr()))
350 // Address will not be translated through TLB, set response, and go!
351 req
->setPaddr(MipsISA::KSeg02Phys(req
->getVaddr()));
355 /* This is an optimization - smallPages is updated every time a TLB operation is performed
356 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
360 VPN
=((req
->getVaddr() >> 11));
362 VPN
=((req
->getVaddr() >> 11) & 0xFFFFFFFC);
364 uint8_t Asid
= req
->getAsid();
365 if(req
->isMisaligned()){ // Unaligned address!
366 AddressErrorFault
*Flt
= new AddressErrorFault();
367 /* BadVAddr must be set */
368 Flt
->BadVAddr
= req
->getVaddr();
371 MipsISA::PTE
*pte
= lookup(VPN
,Asid
);
373 {// Ok, found something
374 /* Check for valid bits */
377 if((((req
->getVaddr()) >> pte
->AddrShiftAmount
) & 1) ==0){
389 ItbInvalidFault
*Flt
= new ItbInvalidFault();
390 /* EntryHi VPN, ASID fields must be set */
391 Flt
->EntryHi_Asid
= Asid
;
392 Flt
->EntryHi_VPN2
= (VPN
>>2);
393 Flt
->EntryHi_VPN2X
= (VPN
& 0x3);
395 /* BadVAddr must be set */
396 Flt
->BadVAddr
= req
->getVaddr();
398 /* Context must be set */
399 Flt
->Context_BadVPN2
= (VPN
>> 2);
403 {// Ok, this is really a match, set paddr
411 PAddr
>>= (pte
->AddrShiftAmount
-12);
412 PAddr
<<= pte
->AddrShiftAmount
;
413 PAddr
|= ((req
->getVaddr()) & pte
->OffsetMask
);
414 req
->setPaddr(PAddr
);
420 { // Didn't find any match, return a TLB Refill Exception
422 ItbRefillFault
*Flt
=new ItbRefillFault();
423 /* EntryHi VPN, ASID fields must be set */
424 Flt
->EntryHi_Asid
= Asid
;
425 Flt
->EntryHi_VPN2
= (VPN
>>2);
426 Flt
->EntryHi_VPN2X
= (VPN
& 0x3);
429 /* BadVAddr must be set */
430 Flt
->BadVAddr
= req
->getVaddr();
432 /* Context must be set */
433 Flt
->Context_BadVPN2
= (VPN
>> 2);
437 return checkCacheability(req
);
442 TLB::translateData(RequestPtr req
, ThreadContext
*tc
, bool write
)
445 //@TODO: This should actually use TLB instead of going directly
446 // to the page table in syscall mode.
448 * Check for alignment faults
450 if (req
->getVaddr() & (req
->getSize() - 1)) {
451 DPRINTF(TLB
, "Alignment Fault on %#x, size = %d", req
->getVaddr(),
453 return new AlignmentFault();
457 Process
* p
= tc
->getProcessPtr();
459 Fault fault
= p
->pTable
->translate(req
);
465 if(MipsISA::IsKSeg0(req
->getVaddr()))
467 // Address will not be translated through TLB, set response, and go!
468 req
->setPaddr(MipsISA::KSeg02Phys(req
->getVaddr()));
469 if(MipsISA::getOperatingMode(tc
->readMiscReg(MipsISA::Status
)) != mode_kernel
|| req
->isMisaligned())
471 StoreAddressErrorFault
*Flt
= new StoreAddressErrorFault();
472 /* BadVAddr must be set */
473 Flt
->BadVAddr
= req
->getVaddr();
478 else if(MipsISA::IsKSeg1(req
->getVaddr()))
480 // Address will not be translated through TLB, set response, and go!
481 req
->setPaddr(MipsISA::KSeg02Phys(req
->getVaddr()));
485 /* This is an optimization - smallPages is updated every time a TLB operation is performed
486 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
488 Addr VPN
=((req
->getVaddr() >> 11) & 0xFFFFFFFC);
490 VPN
=((req
->getVaddr() >> 11));
492 uint8_t Asid
= req
->getAsid();
493 MipsISA::PTE
*pte
= lookup(VPN
,Asid
);
494 if(req
->isMisaligned()){ // Unaligned address!
495 StoreAddressErrorFault
*Flt
= new StoreAddressErrorFault();
496 /* BadVAddr must be set */
497 Flt
->BadVAddr
= req
->getVaddr();
501 {// Ok, found something
502 /* Check for valid bits */
506 if(((((req
->getVaddr()) >> pte
->AddrShiftAmount
) & 1)) ==0){
522 DtbInvalidFault
*Flt
= new DtbInvalidFault();
523 /* EntryHi VPN, ASID fields must be set */
524 Flt
->EntryHi_Asid
= Asid
;
525 Flt
->EntryHi_VPN2
= (VPN
>>2);
526 Flt
->EntryHi_VPN2X
= (VPN
& 0x3);
529 /* BadVAddr must be set */
530 Flt
->BadVAddr
= req
->getVaddr();
532 /* Context must be set */
533 Flt
->Context_BadVPN2
= (VPN
>> 2);
538 {// Ok, this is really a match, set paddr
542 TLBModifiedFault
*Flt
= new TLBModifiedFault();
543 /* EntryHi VPN, ASID fields must be set */
544 Flt
->EntryHi_Asid
= Asid
;
545 Flt
->EntryHi_VPN2
= (VPN
>>2);
546 Flt
->EntryHi_VPN2X
= (VPN
& 0x3);
549 /* BadVAddr must be set */
550 Flt
->BadVAddr
= req
->getVaddr();
552 /* Context must be set */
553 Flt
->Context_BadVPN2
= (VPN
>> 2);
563 PAddr
>>= (pte
->AddrShiftAmount
-12);
564 PAddr
<<= pte
->AddrShiftAmount
;
565 PAddr
|= ((req
->getVaddr()) & pte
->OffsetMask
);
566 req
->setPaddr(PAddr
);
570 { // Didn't find any match, return a TLB Refill Exception
572 DtbRefillFault
*Flt
=new DtbRefillFault();
573 /* EntryHi VPN, ASID fields must be set */
574 Flt
->EntryHi_Asid
= Asid
;
575 Flt
->EntryHi_VPN2
= (VPN
>>2);
576 Flt
->EntryHi_VPN2X
= (VPN
& 0x3);
579 /* BadVAddr must be set */
580 Flt
->BadVAddr
= req
->getVaddr();
582 /* Context must be set */
583 Flt
->Context_BadVPN2
= (VPN
>> 2);
587 return checkCacheability(req
);
592 TLB::translateAtomic(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
595 return translateInst(req
, tc
);
597 return translateData(req
, tc
, mode
== Write
);
601 TLB::translateTiming(RequestPtr req
, ThreadContext
*tc
,
602 Translation
*translation
, Mode mode
)
605 translation
->finish(translateAtomic(req
, tc
, mode
), req
, tc
, mode
);
610 TLB::index(bool advance
)
612 MipsISA::PTE
*pte
= &table
[nlu
];
621 MipsTLBParams::create()
623 return new MipsISA::TLB(this);