ARM: Move the remaining microops out of the decoder and into the ISA desc.
[gem5.git] / src / arch / mips / tlb.cc
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/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"
49
50
51 using namespace std;
52 using namespace MipsISA;
53
54 ///////////////////////////////////////////////////////////////////////
55 //
56 // MIPS TLB
57 //
58
59 #define MODE2MASK(X) (1 << (X))
60
61 TLB::TLB(const Params *p)
62 : BaseTLB(p), size(p->size), nlu(0)
63 {
64 table = new MipsISA::PTE[size];
65 memset(table, 0, sizeof(MipsISA::PTE[size]));
66 smallPages=0;
67 }
68
69 TLB::~TLB()
70 {
71 if (table)
72 delete [] table;
73 }
74
75 // look up an entry in the TLB
76 MipsISA::PTE *
77 TLB::lookup(Addr vpn, uint8_t asn) const
78 {
79 // assume not found...
80 MipsISA::PTE *retval = NULL;
81 PageTable::const_iterator i = lookupTable.find(vpn);
82 if (i != lookupTable.end()) {
83 while (i->first == vpn) {
84 int index = i->second;
85 MipsISA::PTE *pte = &table[index];
86
87 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
88 Addr Mask = pte->Mask;
89 Addr InvMask = ~Mask;
90 Addr VPN = pte->VPN;
91 // warn("Valid: %d - %d\n",pte->V0,pte->V1);
92 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid)))
93 { // We have a VPN + ASID Match
94 retval = pte;
95 break;
96 }
97 ++i;
98 }
99 }
100
101 DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
102 retval ? "hit" : "miss", retval ? retval->PFN1 : 0);
103 return retval;
104 }
105
106 MipsISA::PTE* TLB::getEntry(unsigned Index) const
107 {
108 // Make sure that Index is valid
109 assert(Index<size);
110 return &table[Index];
111 }
112
113 int TLB::probeEntry(Addr vpn,uint8_t asn) const
114 {
115 // assume not found...
116 MipsISA::PTE *retval = NULL;
117 int Ind=-1;
118 PageTable::const_iterator i = lookupTable.find(vpn);
119 if (i != lookupTable.end()) {
120 while (i->first == vpn) {
121 int index = i->second;
122 MipsISA::PTE *pte = &table[index];
123
124 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
125 Addr Mask = pte->Mask;
126 Addr InvMask = ~Mask;
127 Addr VPN = pte->VPN;
128 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid)))
129 { // We have a VPN + ASID Match
130 retval = pte;
131 Ind = index;
132 break;
133 }
134
135 ++i;
136 }
137 }
138 DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind);
139 return Ind;
140 }
141 Fault inline
142 TLB::checkCacheability(RequestPtr &req)
143 {
144 Addr VAddrUncacheable = 0xA0000000;
145 // In MIPS, cacheability is controlled by certain bits of the virtual address
146 // or by the TLB entry
147 if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
148 // mark request as uncacheable
149 req->setFlags(Request::UNCACHEABLE);
150 }
151 return NoFault;
152 }
153 void TLB::insertAt(MipsISA::PTE &pte, unsigned Index, int _smallPages)
154 {
155 smallPages=_smallPages;
156 if(Index > size){
157 warn("Attempted to write at index (%d) beyond TLB size (%d)",Index,size);
158 } else {
159 // Update TLB
160 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),
161 ((pte.PFN1 <<6) | (pte.C1 << 3) | (pte.D1 << 2) | (pte.V1 <<1) | pte.G));
162 if(table[Index].V0 == true || table[Index].V1 == true){ // Previous entry is valid
163 PageTable::iterator i = lookupTable.find(table[Index].VPN);
164 lookupTable.erase(i);
165 }
166 table[Index]=pte;
167 // Update fast lookup table
168 lookupTable.insert(make_pair(table[Index].VPN, Index));
169 // int TestIndex=probeEntry(pte.VPN,pte.asid);
170 // warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask);
171 }
172
173 }
174
175 // insert a new TLB entry
176 void
177 TLB::insert(Addr addr, MipsISA::PTE &pte)
178 {
179 fatal("TLB Insert not yet implemented\n");
180
181
182 /* MipsISA::VAddr vaddr = addr;
183 if (table[nlu].valid) {
184 Addr oldvpn = table[nlu].tag;
185 PageTable::iterator i = lookupTable.find(oldvpn);
186
187 if (i == lookupTable.end())
188 panic("TLB entry not found in lookupTable");
189
190 int index;
191 while ((index = i->second) != nlu) {
192 if (table[index].tag != oldvpn)
193 panic("TLB entry not found in lookupTable");
194
195 ++i;
196 }
197
198 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
199
200 lookupTable.erase(i);
201 }
202
203 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
204
205 table[nlu] = pte;
206 table[nlu].tag = vaddr.vpn();
207 table[nlu].valid = true;
208
209 lookupTable.insert(make_pair(vaddr.vpn(), nlu));
210 nextnlu();
211 */
212 }
213
214 void
215 TLB::flushAll()
216 {
217 DPRINTF(TLB, "flushAll\n");
218 memset(table, 0, sizeof(MipsISA::PTE[size]));
219 lookupTable.clear();
220 nlu = 0;
221 }
222
223 void
224 TLB::serialize(ostream &os)
225 {
226 SERIALIZE_SCALAR(size);
227 SERIALIZE_SCALAR(nlu);
228
229 for (int i = 0; i < size; i++) {
230 nameOut(os, csprintf("%s.PTE%d", name(), i));
231 table[i].serialize(os);
232 }
233 }
234
235 void
236 TLB::unserialize(Checkpoint *cp, const string &section)
237 {
238 UNSERIALIZE_SCALAR(size);
239 UNSERIALIZE_SCALAR(nlu);
240
241 for (int i = 0; i < size; i++) {
242 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
243 if (table[i].V0 || table[i].V1) {
244 lookupTable.insert(make_pair(table[i].VPN, i));
245 }
246 }
247 }
248
249 void
250 TLB::regStats()
251 {
252 read_hits
253 .name(name() + ".read_hits")
254 .desc("DTB read hits")
255 ;
256
257 read_misses
258 .name(name() + ".read_misses")
259 .desc("DTB read misses")
260 ;
261
262
263 read_accesses
264 .name(name() + ".read_accesses")
265 .desc("DTB read accesses")
266 ;
267
268 write_hits
269 .name(name() + ".write_hits")
270 .desc("DTB write hits")
271 ;
272
273 write_misses
274 .name(name() + ".write_misses")
275 .desc("DTB write misses")
276 ;
277
278
279 write_accesses
280 .name(name() + ".write_accesses")
281 .desc("DTB write accesses")
282 ;
283
284 hits
285 .name(name() + ".hits")
286 .desc("DTB hits")
287 ;
288
289 misses
290 .name(name() + ".misses")
291 .desc("DTB misses")
292 ;
293
294 invalids
295 .name(name() + ".invalids")
296 .desc("DTB access violations")
297 ;
298
299 accesses
300 .name(name() + ".accesses")
301 .desc("DTB accesses")
302 ;
303
304 hits = read_hits + write_hits;
305 misses = read_misses + write_misses;
306 accesses = read_accesses + write_accesses;
307 }
308
309 Fault
310 TLB::translateInst(RequestPtr req, ThreadContext *tc)
311 {
312 #if !FULL_SYSTEM
313 Process * p = tc->getProcessPtr();
314
315 Fault fault = p->pTable->translate(req);
316 if(fault != NoFault)
317 return fault;
318
319 return NoFault;
320 #else
321 if(MipsISA::IsKSeg0(req->getVaddr()))
322 {
323 // Address will not be translated through TLB, set response, and go!
324 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
325 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
326 {
327 AddressErrorFault *Flt = new AddressErrorFault();
328 /* BadVAddr must be set */
329 Flt->BadVAddr = req->getVaddr();
330 return Flt;
331 }
332 }
333 else if(MipsISA::IsKSeg1(req->getVaddr()))
334 {
335 // Address will not be translated through TLB, set response, and go!
336 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
337 }
338 else
339 {
340 /* This is an optimization - smallPages is updated every time a TLB operation is performed
341 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
342 do a TLB lookup */
343 Addr VPN;
344 if(smallPages==1){
345 VPN=((req->getVaddr() >> 11));
346 } else {
347 VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
348 }
349 uint8_t Asid = req->getAsid();
350 if(req->isMisaligned()){ // Unaligned address!
351 AddressErrorFault *Flt = new AddressErrorFault();
352 /* BadVAddr must be set */
353 Flt->BadVAddr = req->getVaddr();
354 return Flt;
355 }
356 MipsISA::PTE *pte = lookup(VPN,Asid);
357 if(pte != NULL)
358 {// Ok, found something
359 /* Check for valid bits */
360 int EvenOdd;
361 bool Valid;
362 if((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) ==0){
363 // Check even bits
364 Valid = pte->V0;
365 EvenOdd = 0;
366 } else {
367 // Check odd bits
368 Valid = pte->V1;
369 EvenOdd = 1;
370 }
371
372 if(Valid == false)
373 {//Invalid entry
374 ItbInvalidFault *Flt = new ItbInvalidFault();
375 /* EntryHi VPN, ASID fields must be set */
376 Flt->EntryHi_Asid = Asid;
377 Flt->EntryHi_VPN2 = (VPN>>2);
378 Flt->EntryHi_VPN2X = (VPN & 0x3);
379
380 /* BadVAddr must be set */
381 Flt->BadVAddr = req->getVaddr();
382
383 /* Context must be set */
384 Flt->Context_BadVPN2 = (VPN >> 2);
385 return Flt;
386 }
387 else
388 {// Ok, this is really a match, set paddr
389 // hits++;
390 Addr PAddr;
391 if(EvenOdd == 0){
392 PAddr = pte->PFN0;
393 }else{
394 PAddr = pte->PFN1;
395 }
396 PAddr >>= (pte->AddrShiftAmount-12);
397 PAddr <<= pte->AddrShiftAmount;
398 PAddr |= ((req->getVaddr()) & pte->OffsetMask);
399 req->setPaddr(PAddr);
400
401
402 }
403 }
404 else
405 { // Didn't find any match, return a TLB Refill Exception
406 // misses++;
407 ItbRefillFault *Flt=new ItbRefillFault();
408 /* EntryHi VPN, ASID fields must be set */
409 Flt->EntryHi_Asid = Asid;
410 Flt->EntryHi_VPN2 = (VPN>>2);
411 Flt->EntryHi_VPN2X = (VPN & 0x3);
412
413
414 /* BadVAddr must be set */
415 Flt->BadVAddr = req->getVaddr();
416
417 /* Context must be set */
418 Flt->Context_BadVPN2 = (VPN >> 2);
419 return Flt;
420 }
421 }
422 return checkCacheability(req);
423 #endif
424 }
425
426 Fault
427 TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
428 {
429 #if !FULL_SYSTEM
430 //@TODO: This should actually use TLB instead of going directly
431 // to the page table in syscall mode.
432 /**
433 * Check for alignment faults
434 */
435 if (req->getVaddr() & (req->getSize() - 1)) {
436 DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
437 req->getSize());
438 return new AlignmentFault();
439 }
440
441
442 Process * p = tc->getProcessPtr();
443
444 Fault fault = p->pTable->translate(req);
445 if(fault != NoFault)
446 return fault;
447
448 return NoFault;
449 #else
450 if(MipsISA::IsKSeg0(req->getVaddr()))
451 {
452 // Address will not be translated through TLB, set response, and go!
453 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
454 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
455 {
456 StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
457 /* BadVAddr must be set */
458 Flt->BadVAddr = req->getVaddr();
459
460 return Flt;
461 }
462 }
463 else if(MipsISA::IsKSeg1(req->getVaddr()))
464 {
465 // Address will not be translated through TLB, set response, and go!
466 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
467 }
468 else
469 {
470 /* This is an optimization - smallPages is updated every time a TLB operation is performed
471 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
472 do a TLB lookup */
473 Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
474 if(smallPages==1){
475 VPN=((req->getVaddr() >> 11));
476 }
477 uint8_t Asid = req->getAsid();
478 MipsISA::PTE *pte = lookup(VPN,Asid);
479 if(req->isMisaligned()){ // Unaligned address!
480 StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
481 /* BadVAddr must be set */
482 Flt->BadVAddr = req->getVaddr();
483 return Flt;
484 }
485 if(pte != NULL)
486 {// Ok, found something
487 /* Check for valid bits */
488 int EvenOdd;
489 bool Valid;
490 bool Dirty;
491 if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){
492 // Check even bits
493 Valid = pte->V0;
494 Dirty = pte->D0;
495 EvenOdd = 0;
496
497 } else {
498 // Check odd bits
499 Valid = pte->V1;
500 Dirty = pte->D1;
501 EvenOdd = 1;
502 }
503
504 if(Valid == false)
505 {//Invalid entry
506 // invalids++;
507 DtbInvalidFault *Flt = new DtbInvalidFault();
508 /* EntryHi VPN, ASID fields must be set */
509 Flt->EntryHi_Asid = Asid;
510 Flt->EntryHi_VPN2 = (VPN>>2);
511 Flt->EntryHi_VPN2X = (VPN & 0x3);
512
513
514 /* BadVAddr must be set */
515 Flt->BadVAddr = req->getVaddr();
516
517 /* Context must be set */
518 Flt->Context_BadVPN2 = (VPN >> 2);
519
520 return Flt;
521 }
522 else
523 {// Ok, this is really a match, set paddr
524 // hits++;
525 if(!Dirty)
526 {
527 TLBModifiedFault *Flt = new TLBModifiedFault();
528 /* EntryHi VPN, ASID fields must be set */
529 Flt->EntryHi_Asid = Asid;
530 Flt->EntryHi_VPN2 = (VPN>>2);
531 Flt->EntryHi_VPN2X = (VPN & 0x3);
532
533
534 /* BadVAddr must be set */
535 Flt->BadVAddr = req->getVaddr();
536
537 /* Context must be set */
538 Flt->Context_BadVPN2 = (VPN >> 2);
539 return Flt;
540
541 }
542 Addr PAddr;
543 if(EvenOdd == 0){
544 PAddr = pte->PFN0;
545 }else{
546 PAddr = pte->PFN1;
547 }
548 PAddr >>= (pte->AddrShiftAmount-12);
549 PAddr <<= pte->AddrShiftAmount;
550 PAddr |= ((req->getVaddr()) & pte->OffsetMask);
551 req->setPaddr(PAddr);
552 }
553 }
554 else
555 { // Didn't find any match, return a TLB Refill Exception
556 // misses++;
557 DtbRefillFault *Flt=new DtbRefillFault();
558 /* EntryHi VPN, ASID fields must be set */
559 Flt->EntryHi_Asid = Asid;
560 Flt->EntryHi_VPN2 = (VPN>>2);
561 Flt->EntryHi_VPN2X = (VPN & 0x3);
562
563
564 /* BadVAddr must be set */
565 Flt->BadVAddr = req->getVaddr();
566
567 /* Context must be set */
568 Flt->Context_BadVPN2 = (VPN >> 2);
569 return Flt;
570 }
571 }
572 return checkCacheability(req);
573 #endif
574 }
575
576 Fault
577 TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
578 {
579 if (mode == Execute)
580 return translateInst(req, tc);
581 else
582 return translateData(req, tc, mode == Write);
583 }
584
585 void
586 TLB::translateTiming(RequestPtr req, ThreadContext *tc,
587 Translation *translation, Mode mode)
588 {
589 assert(translation);
590 translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
591 }
592
593
594 MipsISA::PTE &
595 TLB::index(bool advance)
596 {
597 MipsISA::PTE *pte = &table[nlu];
598
599 if (advance)
600 nextnlu();
601
602 return *pte;
603 }
604
605 MipsISA::TLB *
606 MipsTLBParams::create()
607 {
608 return new MipsISA::TLB(this);
609 }