tlb.cc revision 5222:bb733a878f85
1/*
2 * Copyright 2007 MIPS Technologies, Inc.  All Rights Reserved
3 *
4 * This software is part of the M5 simulator.
5 *
6 * THIS IS A LEGAL AGREEMENT.  BY DOWNLOADING, USING, COPYING, CREATING
7 * DERIVATIVE WORKS, AND/OR DISTRIBUTING THIS SOFTWARE YOU ARE AGREEING
8 * TO THESE TERMS AND CONDITIONS.
9 *
10 * Permission is granted to use, copy, create derivative works and
11 * distribute this software and such derivative works for any purpose,
12 * so long as (1) the copyright notice above, this grant of permission,
13 * and the disclaimer below appear in all copies and derivative works
14 * made, (2) the copyright notice above is augmented as appropriate to
15 * reflect the addition of any new copyrightable work in a derivative
16 * work (e.g., Copyright N) <Publication Year> Copyright Owner), and (3)
17 * the name of MIPS Technologies, Inc. ($(B!H(BMIPS$(B!I(B) is not used in any
18 * advertising or publicity pertaining to the use or distribution of
19 * this software without specific, written prior authorization.
20 *
21 * THIS SOFTWARE IS PROVIDED $(B!H(BAS IS.$(B!I(B  MIPS MAKES NO WARRANTIES AND
22 * DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, STATUTORY, IMPLIED OR
23 * OTHERWISE, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
25 * NON-INFRINGEMENT OF THIRD PARTY RIGHTS, REGARDING THIS SOFTWARE.
26 * IN NO EVENT SHALL MIPS BE LIABLE FOR ANY DAMAGES, INCLUDING DIRECT,
27 * INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR PUNITIVE DAMAGES OF
28 * ANY KIND OR NATURE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT,
29 * THIS SOFTWARE AND/OR THE USE OF THIS SOFTWARE, WHETHER SUCH LIABILITY
30 * IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR
31 * STRICT LIABILITY), OR OTHERWISE, EVEN IF MIPS HAS BEEN WARNED OF THE
32 * POSSIBILITY OF ANY SUCH LOSS OR DAMAGE IN ADVANCE.
33 *
34 * Authors: Jaidev P. Patwardhan
35 *
36 */
37
38#include <string>
39#include <vector>
40
41#include "arch/mips/pra_constants.hh"
42#include "arch/mips/pagetable.hh"
43#include "arch/mips/tlb.hh"
44#include "arch/mips/faults.hh"
45#include "arch/mips/utility.hh"
46#include "base/inifile.hh"
47#include "base/str.hh"
48#include "base/trace.hh"
49#include "cpu/thread_context.hh"
50#include "params/MipsDTB.hh"
51#include "params/MipsITB.hh"
52#include "params/MipsTLB.hh"
53#include "params/MipsUTB.hh"
54
55
56using namespace std;
57using namespace MipsISA;
58
59///////////////////////////////////////////////////////////////////////
60//
61//  MIPS TLB
62//
63
64#define MODE2MASK(X)			(1 << (X))
65
66TLB::TLB(const Params *p)
67    : SimObject(p), size(p->size), nlu(0)
68{
69    table = new MipsISA::PTE[size];
70    memset(table, 0, sizeof(MipsISA::PTE[size]));
71    smallPages=0;
72}
73
74TLB::~TLB()
75{
76    if (table)
77        delete [] table;
78}
79
80// look up an entry in the TLB
81MipsISA::PTE *
82TLB::lookup(Addr vpn, uint8_t asn) const
83{
84    // assume not found...
85    MipsISA::PTE *retval = NULL;
86    PageTable::const_iterator i = lookupTable.find(vpn);
87    if (i != lookupTable.end()) {
88        while (i->first == vpn) {
89            int index = i->second;
90            MipsISA::PTE *pte = &table[index];
91
92            /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
93            Addr Mask = pte->Mask;
94            Addr InvMask = ~Mask;
95            Addr VPN  = pte->VPN;
96            //	    warn("Valid: %d - %d\n",pte->V0,pte->V1);
97            if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G  || (asn == pte->asid)))
98              { // We have a VPN + ASID Match
99                retval = pte;
100                break;
101              }
102            ++i;
103        }
104    }
105
106    DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
107            retval ? "hit" : "miss", retval ? retval->PFN1 : 0);
108    return retval;
109}
110
111MipsISA::PTE* TLB::getEntry(unsigned Index) const
112{
113    // Make sure that Index is valid
114    assert(Index<size);
115    return &table[Index];
116}
117
118int TLB::probeEntry(Addr vpn,uint8_t asn) const
119{
120    // assume not found...
121    MipsISA::PTE *retval = NULL;
122    int Ind=-1;
123    PageTable::const_iterator i = lookupTable.find(vpn);
124    if (i != lookupTable.end()) {
125        while (i->first == vpn) {
126            int index = i->second;
127            MipsISA::PTE *pte = &table[index];
128
129            /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
130            Addr Mask = pte->Mask;
131            Addr InvMask = ~Mask;
132            Addr VPN  = pte->VPN;
133            if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G  || (asn == pte->asid)))
134              { // We have a VPN + ASID Match
135                retval = pte;
136                Ind = index;
137                break;
138              }
139
140            ++i;
141        }
142    }
143    DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind);
144    return Ind;
145}
146Fault inline
147TLB::checkCacheability(RequestPtr &req)
148{
149  Addr VAddrUncacheable = 0xA0000000;
150  // In MIPS, cacheability is controlled by certain bits of the virtual address
151  // or by the TLB entry
152  if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
153    // mark request as uncacheable
154    req->setFlags(req->getFlags() | UNCACHEABLE);
155  }
156  return NoFault;
157}
158void TLB::insertAt(MipsISA::PTE &pte, unsigned Index, int _smallPages)
159{
160  smallPages=_smallPages;
161  if(Index > size){
162    warn("Attempted to write at index (%d) beyond TLB size (%d)",Index,size);
163  } else {
164    // Update TLB
165    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),
166            ((pte.PFN1 <<6) | (pte.C1 << 3) | (pte.D1 << 2) | (pte.V1 <<1) | pte.G));
167    if(table[Index].V0 == true || table[Index].V1 == true){ // Previous entry is valid
168      PageTable::iterator i = lookupTable.find(table[Index].VPN);
169      lookupTable.erase(i);
170    }
171    table[Index]=pte;
172    // Update fast lookup table
173    lookupTable.insert(make_pair(table[Index].VPN, Index));
174    //    int TestIndex=probeEntry(pte.VPN,pte.asid);
175    //    warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask);
176  }
177
178}
179
180// insert a new TLB entry
181void
182TLB::insert(Addr addr, MipsISA::PTE &pte)
183{
184  fatal("TLB Insert not yet implemented\n");
185
186
187  /*    MipsISA::VAddr vaddr = addr;
188    if (table[nlu].valid) {
189        Addr oldvpn = table[nlu].tag;
190        PageTable::iterator i = lookupTable.find(oldvpn);
191
192        if (i == lookupTable.end())
193            panic("TLB entry not found in lookupTable");
194
195        int index;
196        while ((index = i->second) != nlu) {
197            if (table[index].tag != oldvpn)
198                panic("TLB entry not found in lookupTable");
199
200            ++i;
201        }
202
203        DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
204
205        lookupTable.erase(i);
206    }
207
208    DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
209
210    table[nlu] = pte;
211    table[nlu].tag = vaddr.vpn();
212    table[nlu].valid = true;
213
214    lookupTable.insert(make_pair(vaddr.vpn(), nlu));
215    nextnlu();
216  */
217}
218
219void
220TLB::flushAll()
221{
222    DPRINTF(TLB, "flushAll\n");
223    memset(table, 0, sizeof(MipsISA::PTE[size]));
224    lookupTable.clear();
225    nlu = 0;
226}
227
228void
229TLB::serialize(ostream &os)
230{
231    SERIALIZE_SCALAR(size);
232    SERIALIZE_SCALAR(nlu);
233
234    for (int i = 0; i < size; i++) {
235        nameOut(os, csprintf("%s.PTE%d", name(), i));
236        table[i].serialize(os);
237    }
238}
239
240void
241TLB::unserialize(Checkpoint *cp, const string &section)
242{
243    UNSERIALIZE_SCALAR(size);
244    UNSERIALIZE_SCALAR(nlu);
245
246    for (int i = 0; i < size; i++) {
247        table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
248        if (table[i].V0 || table[i].V1) {
249            lookupTable.insert(make_pair(table[i].VPN, i));
250        }
251    }
252}
253
254void
255TLB::regStats()
256{
257    read_hits
258        .name(name() + ".read_hits")
259        .desc("DTB read hits")
260        ;
261
262    read_misses
263        .name(name() + ".read_misses")
264        .desc("DTB read misses")
265        ;
266
267
268    read_accesses
269        .name(name() + ".read_accesses")
270        .desc("DTB read accesses")
271        ;
272
273    write_hits
274        .name(name() + ".write_hits")
275        .desc("DTB write hits")
276        ;
277
278    write_misses
279        .name(name() + ".write_misses")
280        .desc("DTB write misses")
281        ;
282
283
284    write_accesses
285        .name(name() + ".write_accesses")
286        .desc("DTB write accesses")
287        ;
288
289    hits
290        .name(name() + ".hits")
291        .desc("DTB hits")
292        ;
293
294    misses
295        .name(name() + ".misses")
296        .desc("DTB misses")
297        ;
298
299    invalids
300        .name(name() + ".invalids")
301        .desc("DTB access violations")
302        ;
303
304    accesses
305        .name(name() + ".accesses")
306        .desc("DTB accesses")
307        ;
308
309    hits = read_hits + write_hits;
310    misses = read_misses + write_misses;
311    accesses = read_accesses + write_accesses;
312}
313
314Fault
315ITB::translate(RequestPtr &req, ThreadContext *tc)
316{
317  if(MipsISA::IsKSeg0(req->getVaddr()))
318    {
319      // Address will not be translated through TLB, set response, and go!
320      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
321      if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
322        {
323          AddressErrorFault *Flt = new AddressErrorFault();
324          /* BadVAddr must be set */
325          Flt->BadVAddr = req->getVaddr();
326          return Flt;
327        }
328    }
329  else if(MipsISA::IsKSeg1(req->getVaddr()))
330    {
331      // Address will not be translated through TLB, set response, and go!
332      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
333    }
334  else
335    {
336      /* This is an optimization - smallPages is updated every time a TLB operation is performed
337         That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
338         do a TLB lookup */
339      Addr VPN;
340      if(smallPages==1){
341        VPN=((req->getVaddr() >> 11));
342      } else {
343        VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
344      }
345      uint8_t Asid = req->getAsid();
346      if(req->isMisaligned()){ // Unaligned address!
347        AddressErrorFault *Flt = new AddressErrorFault();
348        /* BadVAddr must be set */
349        Flt->BadVAddr = req->getVaddr();
350        return Flt;
351      }
352      MipsISA::PTE *pte = lookup(VPN,Asid);
353      if(pte != NULL)
354        {// Ok, found something
355          /* Check for valid bits */
356          int EvenOdd;
357          bool Valid;
358          if((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) ==0){
359            // Check even bits
360            Valid = pte->V0;
361            EvenOdd = 0;
362          } else {
363            // Check odd bits
364            Valid = pte->V1;
365            EvenOdd = 1;
366          }
367
368          if(Valid == false)
369            {//Invalid entry
370              ItbInvalidFault *Flt = new ItbInvalidFault();
371              /* EntryHi VPN, ASID fields must be set */
372              Flt->EntryHi_Asid = Asid;
373              Flt->EntryHi_VPN2 = (VPN>>2);
374              Flt->EntryHi_VPN2X = (VPN & 0x3);
375
376              /* BadVAddr must be set */
377              Flt->BadVAddr = req->getVaddr();
378
379              /* Context must be set */
380              Flt->Context_BadVPN2 = (VPN >> 2);
381              return Flt;
382            }
383          else
384            {// Ok, this is really a match, set paddr
385              //	      hits++;
386              Addr PAddr;
387              if(EvenOdd == 0){
388                PAddr = pte->PFN0;
389              }else{
390                PAddr = pte->PFN1;
391              }
392              PAddr >>= (pte->AddrShiftAmount-12);
393              PAddr <<= pte->AddrShiftAmount;
394              PAddr |= ((req->getVaddr()) & pte->OffsetMask);
395              req->setPaddr(PAddr);
396
397
398            }
399        }
400      else
401        { // Didn't find any match, return a TLB Refill Exception
402          //	  misses++;
403          ItbRefillFault *Flt=new ItbRefillFault();
404          /* EntryHi VPN, ASID fields must be set */
405          Flt->EntryHi_Asid = Asid;
406          Flt->EntryHi_VPN2 = (VPN>>2);
407          Flt->EntryHi_VPN2X = (VPN & 0x3);
408
409
410          /* BadVAddr must be set */
411          Flt->BadVAddr = req->getVaddr();
412
413          /* Context must be set */
414          Flt->Context_BadVPN2 = (VPN >> 2);
415          return Flt;
416        }
417    }
418  return checkCacheability(req);
419}
420
421Fault
422DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
423{
424  if(MipsISA::IsKSeg0(req->getVaddr()))
425    {
426      // Address will not be translated through TLB, set response, and go!
427      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
428      if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
429        {
430          StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
431          /* BadVAddr must be set */
432          Flt->BadVAddr = req->getVaddr();
433
434          return Flt;
435        }
436    }
437  else if(MipsISA::IsKSeg1(req->getVaddr()))
438    {
439      // Address will not be translated through TLB, set response, and go!
440      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
441    }
442  else
443    {
444      /* This is an optimization - smallPages is updated every time a TLB operation is performed
445         That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
446         do a TLB lookup */
447      Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
448      if(smallPages==1){
449        VPN=((req->getVaddr() >> 11));
450      }
451      uint8_t Asid = req->getAsid();
452      MipsISA::PTE *pte = lookup(VPN,Asid);
453      if(req->isMisaligned()){ // Unaligned address!
454        StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
455        /* BadVAddr must be set */
456        Flt->BadVAddr = req->getVaddr();
457        return Flt;
458      }
459      if(pte != NULL)
460        {// Ok, found something
461          /* Check for valid bits */
462          int EvenOdd;
463          bool Valid;
464          bool Dirty;
465          if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){
466            // Check even bits
467            Valid = pte->V0;
468            Dirty = pte->D0;
469            EvenOdd = 0;
470
471          } else {
472            // Check odd bits
473            Valid = pte->V1;
474            Dirty = pte->D1;
475            EvenOdd = 1;
476          }
477
478          if(Valid == false)
479            {//Invalid entry
480              //	      invalids++;
481              DtbInvalidFault *Flt = new DtbInvalidFault();
482              /* EntryHi VPN, ASID fields must be set */
483              Flt->EntryHi_Asid = Asid;
484              Flt->EntryHi_VPN2 = (VPN>>2);
485              Flt->EntryHi_VPN2X = (VPN & 0x3);
486
487
488              /* BadVAddr must be set */
489              Flt->BadVAddr = req->getVaddr();
490
491              /* Context must be set */
492              Flt->Context_BadVPN2 = (VPN >> 2);
493
494              return Flt;
495            }
496          else
497            {// Ok, this is really a match, set paddr
498              //	      hits++;
499              if(!Dirty)
500                {
501                  TLBModifiedFault *Flt = new TLBModifiedFault();
502                  /* EntryHi VPN, ASID fields must be set */
503                  Flt->EntryHi_Asid = Asid;
504                  Flt->EntryHi_VPN2 = (VPN>>2);
505                  Flt->EntryHi_VPN2X = (VPN & 0x3);
506
507
508                  /* BadVAddr must be set */
509                  Flt->BadVAddr = req->getVaddr();
510
511                  /* Context must be set */
512                  Flt->Context_BadVPN2 = (VPN >> 2);
513                  return Flt;
514
515                }
516              Addr PAddr;
517              if(EvenOdd == 0){
518                PAddr = pte->PFN0;
519              }else{
520                PAddr = pte->PFN1;
521              }
522              PAddr >>= (pte->AddrShiftAmount-12);
523              PAddr <<= pte->AddrShiftAmount;
524              PAddr |= ((req->getVaddr()) & pte->OffsetMask);
525              req->setPaddr(PAddr);
526            }
527        }
528      else
529        { // Didn't find any match, return a TLB Refill Exception
530          //	  misses++;
531          DtbRefillFault *Flt=new DtbRefillFault();
532          /* EntryHi VPN, ASID fields must be set */
533          Flt->EntryHi_Asid = Asid;
534          Flt->EntryHi_VPN2 = (VPN>>2);
535          Flt->EntryHi_VPN2X = (VPN & 0x3);
536
537
538          /* BadVAddr must be set */
539          Flt->BadVAddr = req->getVaddr();
540
541          /* Context must be set */
542          Flt->Context_BadVPN2 = (VPN >> 2);
543          return Flt;
544        }
545    }
546    return checkCacheability(req);
547}
548
549///////////////////////////////////////////////////////////////////////
550//
551//  Mips ITB
552//
553ITB::ITB(const Params *p)
554    : TLB(p)
555{}
556
557
558// void
559// ITB::regStats()
560// {
561//   /*    hits - causes failure for some reason
562// 	.name(name() + ".hits")
563// 	.desc("ITB hits");
564//     misses
565// 	.name(name() + ".misses")
566// 	.desc("ITB misses");
567//     acv
568// 	.name(name() + ".acv")
569// 	.desc("ITB acv");
570//     accesses
571// 	.name(name() + ".accesses")
572// 	.desc("ITB accesses");
573
574// 	accesses = hits + misses + invalids; */
575// }
576
577
578
579///////////////////////////////////////////////////////////////////////
580//
581//  Mips DTB
582//
583DTB::DTB(const Params *p)
584    : TLB(p)
585{}
586
587///////////////////////////////////////////////////////////////////////
588//
589//  Mips UTB
590//
591UTB::UTB(const Params *p)
592    : ITB(p), DTB(p)
593{}
594
595
596
597MipsISA::PTE &
598TLB::index(bool advance)
599{
600    MipsISA::PTE *pte = &table[nlu];
601
602    if (advance)
603        nextnlu();
604
605    return *pte;
606}
607
608MipsISA::ITB *
609MipsITBParams::create()
610{
611    return new MipsISA::ITB(this);
612}
613
614MipsISA::DTB *
615MipsDTBParams::create()
616{
617    return new MipsISA::DTB(this);
618}
619
620MipsISA::UTB *
621MipsUTBParams::create()
622{
623    return new MipsISA::UTB(this);
624}
625