tlb.cc revision 4997
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 */
30
31#include <cstring>
32
33#include "arch/sparc/asi.hh"
34#include "arch/sparc/miscregfile.hh"
35#include "arch/sparc/tlb.hh"
36#include "base/bitfield.hh"
37#include "base/trace.hh"
38#include "cpu/thread_context.hh"
39#include "cpu/base.hh"
40#include "mem/packet_access.hh"
41#include "mem/request.hh"
42#include "params/SparcDTB.hh"
43#include "params/SparcITB.hh"
44#include "sim/system.hh"
45
46/* @todo remove some of the magic constants.  -- ali
47 * */
48namespace SparcISA {
49
50TLB::TLB(const std::string &name, int s)
51    : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
52      cacheValid(false)
53{
54    // To make this work you'll have to change the hypervisor and OS
55    if (size > 64)
56        fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
57
58    tlb = new TlbEntry[size];
59    std::memset(tlb, 0, sizeof(TlbEntry) * size);
60
61    for (int x = 0; x < size; x++)
62        freeList.push_back(&tlb[x]);
63
64    c0_tsb_ps0 = 0;
65    c0_tsb_ps1 = 0;
66    c0_config = 0;
67    cx_tsb_ps0 = 0;
68    cx_tsb_ps1 = 0;
69    cx_config = 0;
70    sfsr = 0;
71    tag_access = 0;
72}
73
74void
75TLB::clearUsedBits()
76{
77    MapIter i;
78    for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
79        TlbEntry *t = i->second;
80        if (!t->pte.locked()) {
81            t->used = false;
82            usedEntries--;
83        }
84    }
85}
86
87
88void
89TLB::insert(Addr va, int partition_id, int context_id, bool real,
90        const PageTableEntry& PTE, int entry)
91{
92
93
94    MapIter i;
95    TlbEntry *new_entry = NULL;
96//    TlbRange tr;
97    int x;
98
99    cacheValid = false;
100    va &= ~(PTE.size()-1);
101 /*   tr.va = va;
102    tr.size = PTE.size() - 1;
103    tr.contextId = context_id;
104    tr.partitionId = partition_id;
105    tr.real = real;
106*/
107
108    DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
109            va, PTE.paddr(), partition_id, context_id, (int)real, entry);
110
111    // Demap any entry that conflicts
112    for (x = 0; x < size; x++) {
113        if (tlb[x].range.real == real &&
114            tlb[x].range.partitionId == partition_id &&
115            tlb[x].range.va < va + PTE.size() - 1 &&
116            tlb[x].range.va + tlb[x].range.size >= va &&
117            (real || tlb[x].range.contextId == context_id ))
118        {
119            if (tlb[x].valid) {
120                freeList.push_front(&tlb[x]);
121                DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);
122
123                tlb[x].valid = false;
124                if (tlb[x].used) {
125                    tlb[x].used = false;
126                    usedEntries--;
127                }
128                lookupTable.erase(tlb[x].range);
129            }
130        }
131    }
132
133
134/*
135    i = lookupTable.find(tr);
136    if (i != lookupTable.end()) {
137        i->second->valid = false;
138        if (i->second->used) {
139            i->second->used = false;
140            usedEntries--;
141        }
142        freeList.push_front(i->second);
143        DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
144                i->second);
145        lookupTable.erase(i);
146    }
147*/
148
149    if (entry != -1) {
150        assert(entry < size && entry >= 0);
151        new_entry = &tlb[entry];
152    } else {
153        if (!freeList.empty()) {
154            new_entry = freeList.front();
155        } else {
156            x = lastReplaced;
157            do {
158                ++x;
159                if (x == size)
160                    x = 0;
161                if (x == lastReplaced)
162                    goto insertAllLocked;
163            } while (tlb[x].pte.locked());
164            lastReplaced = x;
165            new_entry = &tlb[x];
166        }
167        /*
168        for (x = 0; x < size; x++) {
169            if (!tlb[x].valid || !tlb[x].used)  {
170                new_entry = &tlb[x];
171                break;
172            }
173        }*/
174    }
175
176insertAllLocked:
177    // Update the last ently if their all locked
178    if (!new_entry) {
179        new_entry = &tlb[size-1];
180    }
181
182    freeList.remove(new_entry);
183    if (new_entry->valid && new_entry->used)
184        usedEntries--;
185    if (new_entry->valid)
186        lookupTable.erase(new_entry->range);
187
188
189    assert(PTE.valid());
190    new_entry->range.va = va;
191    new_entry->range.size = PTE.size() - 1;
192    new_entry->range.partitionId = partition_id;
193    new_entry->range.contextId = context_id;
194    new_entry->range.real = real;
195    new_entry->pte = PTE;
196    new_entry->used = true;;
197    new_entry->valid = true;
198    usedEntries++;
199
200
201
202    i = lookupTable.insert(new_entry->range, new_entry);
203    assert(i != lookupTable.end());
204
205    // If all entries have there used bit set, clear it on them all, but the
206    // one we just inserted
207    if (usedEntries == size) {
208        clearUsedBits();
209        new_entry->used = true;
210        usedEntries++;
211    }
212
213}
214
215
216TlbEntry*
217TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool
218        update_used)
219{
220    MapIter i;
221    TlbRange tr;
222    TlbEntry *t;
223
224    DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
225            va, partition_id, context_id, real);
226    // Assemble full address structure
227    tr.va = va;
228    tr.size = MachineBytes;
229    tr.contextId = context_id;
230    tr.partitionId = partition_id;
231    tr.real = real;
232
233    // Try to find the entry
234    i = lookupTable.find(tr);
235    if (i == lookupTable.end()) {
236        DPRINTF(TLB, "TLB: No valid entry found\n");
237        return NULL;
238    }
239
240    // Mark the entries used bit and clear other used bits in needed
241    t = i->second;
242    DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
243            t->pte.size());
244
245    // Update the used bits only if this is a real access (not a fake one from
246    // virttophys()
247    if (!t->used && update_used) {
248        t->used = true;
249        usedEntries++;
250        if (usedEntries == size) {
251            clearUsedBits();
252            t->used = true;
253            usedEntries++;
254        }
255    }
256
257    return t;
258}
259
260void
261TLB::dumpAll()
262{
263    MapIter i;
264    for (int x = 0; x < size; x++) {
265        if (tlb[x].valid) {
266           DPRINTFN("%4d:  %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
267                   x, tlb[x].range.partitionId, tlb[x].range.contextId,
268                   tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
269                   tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
270        }
271    }
272}
273
274void
275TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
276{
277    TlbRange tr;
278    MapIter i;
279
280    DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
281            va, partition_id, context_id, real);
282
283    cacheValid = false;
284
285    // Assemble full address structure
286    tr.va = va;
287    tr.size = MachineBytes;
288    tr.contextId = context_id;
289    tr.partitionId = partition_id;
290    tr.real = real;
291
292    // Demap any entry that conflicts
293    i = lookupTable.find(tr);
294    if (i != lookupTable.end()) {
295        DPRINTF(IPR, "TLB: Demapped page\n");
296        i->second->valid = false;
297        if (i->second->used) {
298            i->second->used = false;
299            usedEntries--;
300        }
301        freeList.push_front(i->second);
302        lookupTable.erase(i);
303    }
304}
305
306void
307TLB::demapContext(int partition_id, int context_id)
308{
309    int x;
310    DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
311            partition_id, context_id);
312    cacheValid = false;
313    for (x = 0; x < size; x++) {
314        if (tlb[x].range.contextId == context_id &&
315            tlb[x].range.partitionId == partition_id) {
316            if (tlb[x].valid == true) {
317                freeList.push_front(&tlb[x]);
318            }
319            tlb[x].valid = false;
320            if (tlb[x].used) {
321                tlb[x].used = false;
322                usedEntries--;
323            }
324            lookupTable.erase(tlb[x].range);
325        }
326    }
327}
328
329void
330TLB::demapAll(int partition_id)
331{
332    int x;
333    DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
334    cacheValid = false;
335    for (x = 0; x < size; x++) {
336        if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
337            if (tlb[x].valid == true){
338                freeList.push_front(&tlb[x]);
339            }
340            tlb[x].valid = false;
341            if (tlb[x].used) {
342                tlb[x].used = false;
343                usedEntries--;
344            }
345            lookupTable.erase(tlb[x].range);
346        }
347    }
348}
349
350void
351TLB::invalidateAll()
352{
353    int x;
354    cacheValid = false;
355
356    freeList.clear();
357    lookupTable.clear();
358    for (x = 0; x < size; x++) {
359        if (tlb[x].valid == true)
360            freeList.push_back(&tlb[x]);
361        tlb[x].valid = false;
362        tlb[x].used = false;
363    }
364    usedEntries = 0;
365}
366
367uint64_t
368TLB::TteRead(int entry) {
369    if (entry >= size)
370        panic("entry: %d\n", entry);
371
372    assert(entry < size);
373    if (tlb[entry].valid)
374        return tlb[entry].pte();
375    else
376        return (uint64_t)-1ll;
377}
378
379uint64_t
380TLB::TagRead(int entry) {
381    assert(entry < size);
382    uint64_t tag;
383    if (!tlb[entry].valid)
384        return (uint64_t)-1ll;
385
386    tag = tlb[entry].range.contextId;
387    tag |= tlb[entry].range.va;
388    tag |= (uint64_t)tlb[entry].range.partitionId << 61;
389    tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
390    tag |= (uint64_t)~tlb[entry].pte._size() << 56;
391    return tag;
392}
393
394bool
395TLB::validVirtualAddress(Addr va, bool am)
396{
397    if (am)
398        return true;
399    if (va >= StartVAddrHole && va <= EndVAddrHole)
400        return false;
401    return true;
402}
403
404void
405TLB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi)
406{
407    if (sfsr & 0x1)
408        sfsr = 0x3;
409    else
410        sfsr = 1;
411
412    if (write)
413        sfsr |= 1 << 2;
414    sfsr |= ct << 4;
415    if (se)
416        sfsr |= 1 << 6;
417    sfsr |= ft << 7;
418    sfsr |= asi << 16;
419}
420
421void
422TLB::writeTagAccess(Addr va, int context)
423{
424    DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n",
425            va, context, mbits(va, 63,13) | mbits(context,12,0));
426
427    tag_access = mbits(va, 63,13) | mbits(context,12,0);
428}
429
430void
431ITB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi)
432{
433    DPRINTF(TLB, "TLB: ITB Fault:  w=%d ct=%d ft=%d asi=%d\n",
434             (int)write, ct, ft, asi);
435    TLB::writeSfsr(write, ct, se, ft, asi);
436}
437
438void
439DTB::writeSfsr(Addr a, bool write, ContextType ct,
440        bool se, FaultTypes ft, int asi)
441{
442    DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
443            a, (int)write, ct, ft, asi);
444    TLB::writeSfsr(write, ct, se, ft, asi);
445    sfar = a;
446}
447
448Fault
449ITB::translate(RequestPtr &req, ThreadContext *tc)
450{
451    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
452
453    Addr vaddr = req->getVaddr();
454    TlbEntry *e;
455
456    assert(req->getAsi() == ASI_IMPLICIT);
457
458    DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
459            vaddr, req->getSize());
460
461    // Be fast if we can!
462    if (cacheValid && cacheState == tlbdata) {
463        if (cacheEntry) {
464            if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
465                cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
466                    req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
467                                  vaddr & cacheEntry->pte.size()-1 );
468                    return NoFault;
469            }
470        } else {
471            req->setPaddr(vaddr & PAddrImplMask);
472            return NoFault;
473        }
474    }
475
476    bool hpriv = bits(tlbdata,0,0);
477    bool red = bits(tlbdata,1,1);
478    bool priv = bits(tlbdata,2,2);
479    bool addr_mask = bits(tlbdata,3,3);
480    bool lsu_im = bits(tlbdata,4,4);
481
482    int part_id = bits(tlbdata,15,8);
483    int tl = bits(tlbdata,18,16);
484    int pri_context = bits(tlbdata,47,32);
485    int context;
486    ContextType ct;
487    int asi;
488    bool real = false;
489
490    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
491           priv, hpriv, red, lsu_im, part_id);
492
493    if (tl > 0) {
494        asi = ASI_N;
495        ct = Nucleus;
496        context = 0;
497    } else {
498        asi = ASI_P;
499        ct = Primary;
500        context = pri_context;
501    }
502
503    if ( hpriv || red ) {
504        cacheValid = true;
505        cacheState = tlbdata;
506        cacheEntry = NULL;
507        req->setPaddr(vaddr & PAddrImplMask);
508        return NoFault;
509    }
510
511    // If the access is unaligned trap
512    if (vaddr & 0x3) {
513        writeSfsr(false, ct, false, OtherFault, asi);
514        return new MemAddressNotAligned;
515    }
516
517    if (addr_mask)
518        vaddr = vaddr & VAddrAMask;
519
520    if (!validVirtualAddress(vaddr, addr_mask)) {
521        writeSfsr(false, ct, false, VaOutOfRange, asi);
522        return new InstructionAccessException;
523    }
524
525    if (!lsu_im) {
526        e = lookup(vaddr, part_id, true);
527        real = true;
528        context = 0;
529    } else {
530        e = lookup(vaddr, part_id, false, context);
531    }
532
533    if (e == NULL || !e->valid) {
534        writeTagAccess(vaddr, context);
535        if (real)
536            return new InstructionRealTranslationMiss;
537        else
538#if FULL_SYSTEM
539            return new FastInstructionAccessMMUMiss;
540#else
541            return new FastInstructionAccessMMUMiss(req->getVaddr());
542#endif
543    }
544
545    // were not priviledged accesing priv page
546    if (!priv && e->pte.priv()) {
547        writeTagAccess(vaddr, context);
548        writeSfsr(false, ct, false, PrivViolation, asi);
549        return new InstructionAccessException;
550    }
551
552    // cache translation date for next translation
553    cacheValid = true;
554    cacheState = tlbdata;
555    cacheEntry = e;
556
557    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
558                  vaddr & e->pte.size()-1 );
559    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
560    return NoFault;
561}
562
563
564
565Fault
566DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
567{
568    /* @todo this could really use some profiling and fixing to make it faster! */
569    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
570    Addr vaddr = req->getVaddr();
571    Addr size = req->getSize();
572    ASI asi;
573    asi = (ASI)req->getAsi();
574    bool implicit = false;
575    bool hpriv = bits(tlbdata,0,0);
576    bool unaligned = (vaddr & size-1);
577
578    DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
579            vaddr, size, asi);
580
581    if (lookupTable.size() != 64 - freeList.size())
582       panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(),
583               freeList.size());
584    if (asi == ASI_IMPLICIT)
585        implicit = true;
586
587    // Only use the fast path here if there doesn't need to be an unaligned
588    // trap later
589    if (!unaligned) {
590        if (hpriv && implicit) {
591            req->setPaddr(vaddr & PAddrImplMask);
592            return NoFault;
593        }
594
595        // Be fast if we can!
596        if (cacheValid &&  cacheState == tlbdata) {
597
598
599
600            if (cacheEntry[0]) {
601                TlbEntry *ce = cacheEntry[0];
602                Addr ce_va = ce->range.va;
603                if (cacheAsi[0] == asi &&
604                    ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
605                    (!write || ce->pte.writable())) {
606                        req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
607                        if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
608                            req->setFlags(req->getFlags() | UNCACHEABLE);
609                        DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
610                        return NoFault;
611                } // if matched
612            } // if cache entry valid
613            if (cacheEntry[1]) {
614                TlbEntry *ce = cacheEntry[1];
615                Addr ce_va = ce->range.va;
616                if (cacheAsi[1] == asi &&
617                    ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
618                    (!write || ce->pte.writable())) {
619                        req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
620                        if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
621                            req->setFlags(req->getFlags() | UNCACHEABLE);
622                        DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
623                        return NoFault;
624                } // if matched
625            } // if cache entry valid
626        }
627    }
628
629    bool red = bits(tlbdata,1,1);
630    bool priv = bits(tlbdata,2,2);
631    bool addr_mask = bits(tlbdata,3,3);
632    bool lsu_dm = bits(tlbdata,5,5);
633
634    int part_id = bits(tlbdata,15,8);
635    int tl = bits(tlbdata,18,16);
636    int pri_context = bits(tlbdata,47,32);
637    int sec_context = bits(tlbdata,63,48);
638
639    bool real = false;
640    ContextType ct = Primary;
641    int context = 0;
642
643    TlbEntry *e;
644
645    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
646           priv, hpriv, red, lsu_dm, part_id);
647
648    if (implicit) {
649        if (tl > 0) {
650            asi = ASI_N;
651            ct = Nucleus;
652            context = 0;
653        } else {
654            asi = ASI_P;
655            ct = Primary;
656            context = pri_context;
657        }
658    } else {
659        // We need to check for priv level/asi priv
660        if (!priv && !hpriv && !AsiIsUnPriv(asi)) {
661            // It appears that context should be Nucleus in these cases?
662            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
663            return new PrivilegedAction;
664        }
665
666        if (!hpriv && AsiIsHPriv(asi)) {
667            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
668            return new DataAccessException;
669        }
670
671        if (AsiIsPrimary(asi)) {
672            context = pri_context;
673            ct = Primary;
674        } else if (AsiIsSecondary(asi)) {
675            context = sec_context;
676            ct = Secondary;
677        } else if (AsiIsNucleus(asi)) {
678            ct = Nucleus;
679            context = 0;
680        } else {  // ????
681            ct = Primary;
682            context = pri_context;
683        }
684    }
685
686    if (!implicit && asi != ASI_P && asi != ASI_S) {
687        if (AsiIsLittle(asi))
688            panic("Little Endian ASIs not supported\n");
689
690        //XXX It's unclear from looking at the documentation how a no fault
691        //load differs from a regular one, other than what happens concerning
692        //nfo and e bits in the TTE
693//        if (AsiIsNoFault(asi))
694//            panic("No Fault ASIs not supported\n");
695
696        if (AsiIsPartialStore(asi))
697            panic("Partial Store ASIs not supported\n");
698
699        if (AsiIsCmt(asi))
700            panic("Cmt ASI registers not implmented\n");
701
702        if (AsiIsInterrupt(asi))
703            goto handleIntRegAccess;
704        if (AsiIsMmu(asi))
705            goto handleMmuRegAccess;
706        if (AsiIsScratchPad(asi))
707            goto handleScratchRegAccess;
708        if (AsiIsQueue(asi))
709            goto handleQueueRegAccess;
710        if (AsiIsSparcError(asi))
711            goto handleSparcErrorRegAccess;
712
713        if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) &&
714                !AsiIsTwin(asi) && !AsiIsBlock(asi) && !AsiIsNoFault(asi))
715            panic("Accessing ASI %#X. Should we?\n", asi);
716    }
717
718    // If the asi is unaligned trap
719    if (unaligned) {
720        writeSfsr(vaddr, false, ct, false, OtherFault, asi);
721        return new MemAddressNotAligned;
722    }
723
724    if (addr_mask)
725        vaddr = vaddr & VAddrAMask;
726
727    if (!validVirtualAddress(vaddr, addr_mask)) {
728        writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi);
729        return new DataAccessException;
730    }
731
732
733    if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {
734        real = true;
735        context = 0;
736    };
737
738    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
739        req->setPaddr(vaddr & PAddrImplMask);
740        return NoFault;
741    }
742
743    e = lookup(vaddr, part_id, real, context);
744
745    if (e == NULL || !e->valid) {
746        writeTagAccess(vaddr, context);
747        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
748        if (real)
749            return new DataRealTranslationMiss;
750        else
751#if FULL_SYSTEM
752            return new FastDataAccessMMUMiss;
753#else
754            return new FastDataAccessMMUMiss(req->getVaddr());
755#endif
756
757    }
758
759    if (!priv && e->pte.priv()) {
760        writeTagAccess(vaddr, context);
761        writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
762        return new DataAccessException;
763    }
764
765    if (write && !e->pte.writable()) {
766        writeTagAccess(vaddr, context);
767        writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
768        return new FastDataAccessProtection;
769    }
770
771    if (e->pte.nofault() && !AsiIsNoFault(asi)) {
772        writeTagAccess(vaddr, context);
773        writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
774        return new DataAccessException;
775    }
776
777    if (e->pte.sideffect() && AsiIsNoFault(asi)) {
778        writeTagAccess(vaddr, context);
779        writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi);
780        return new DataAccessException;
781    }
782
783
784    if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
785        req->setFlags(req->getFlags() | UNCACHEABLE);
786
787    // cache translation date for next translation
788    cacheState = tlbdata;
789    if (!cacheValid) {
790        cacheEntry[1] = NULL;
791        cacheEntry[0] = NULL;
792    }
793
794    if (cacheEntry[0] != e && cacheEntry[1] != e) {
795        cacheEntry[1] = cacheEntry[0];
796        cacheEntry[0] = e;
797        cacheAsi[1] = cacheAsi[0];
798        cacheAsi[0] = asi;
799        if (implicit)
800            cacheAsi[0] = (ASI)0;
801    }
802    cacheValid = true;
803    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
804                  vaddr & e->pte.size()-1);
805    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
806    return NoFault;
807
808    /** Normal flow ends here. */
809handleIntRegAccess:
810    if (!hpriv) {
811        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
812        if (priv)
813            return new DataAccessException;
814         else
815            return new PrivilegedAction;
816    }
817
818    if (asi == ASI_SWVR_UDB_INTR_W && !write ||
819                    asi == ASI_SWVR_UDB_INTR_R && write) {
820        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
821        return new DataAccessException;
822    }
823
824    goto regAccessOk;
825
826
827handleScratchRegAccess:
828    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
829        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
830        return new DataAccessException;
831    }
832    goto regAccessOk;
833
834handleQueueRegAccess:
835    if (!priv  && !hpriv) {
836        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
837        return new PrivilegedAction;
838    }
839    if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
840        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
841        return new DataAccessException;
842    }
843    goto regAccessOk;
844
845handleSparcErrorRegAccess:
846    if (!hpriv) {
847        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
848        if (priv)
849            return new DataAccessException;
850         else
851            return new PrivilegedAction;
852    }
853    goto regAccessOk;
854
855
856regAccessOk:
857handleMmuRegAccess:
858    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
859    req->setMmapedIpr(true);
860    req->setPaddr(req->getVaddr());
861    return NoFault;
862};
863
864#if FULL_SYSTEM
865
866Tick
867DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
868{
869    Addr va = pkt->getAddr();
870    ASI asi = (ASI)pkt->req->getAsi();
871    uint64_t temp;
872
873    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
874         (uint32_t)pkt->req->getAsi(), pkt->getAddr());
875
876    ITB * itb = tc->getITBPtr();
877
878    switch (asi) {
879      case ASI_LSU_CONTROL_REG:
880        assert(va == 0);
881        pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL));
882        break;
883      case ASI_MMU:
884        switch (va) {
885          case 0x8:
886            pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT));
887            break;
888          case 0x10:
889            pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT));
890            break;
891          default:
892            goto doMmuReadError;
893        }
894        break;
895      case ASI_QUEUE:
896        pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
897                    (va >> 4) - 0x3c));
898        break;
899      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
900        assert(va == 0);
901        pkt->set(c0_tsb_ps0);
902        break;
903      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
904        assert(va == 0);
905        pkt->set(c0_tsb_ps1);
906        break;
907      case ASI_DMMU_CTXT_ZERO_CONFIG:
908        assert(va == 0);
909        pkt->set(c0_config);
910        break;
911      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
912        assert(va == 0);
913        pkt->set(itb->c0_tsb_ps0);
914        break;
915      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
916        assert(va == 0);
917        pkt->set(itb->c0_tsb_ps1);
918        break;
919      case ASI_IMMU_CTXT_ZERO_CONFIG:
920        assert(va == 0);
921        pkt->set(itb->c0_config);
922        break;
923      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
924        assert(va == 0);
925        pkt->set(cx_tsb_ps0);
926        break;
927      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
928        assert(va == 0);
929        pkt->set(cx_tsb_ps1);
930        break;
931      case ASI_DMMU_CTXT_NONZERO_CONFIG:
932        assert(va == 0);
933        pkt->set(cx_config);
934        break;
935      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
936        assert(va == 0);
937        pkt->set(itb->cx_tsb_ps0);
938        break;
939      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
940        assert(va == 0);
941        pkt->set(itb->cx_tsb_ps1);
942        break;
943      case ASI_IMMU_CTXT_NONZERO_CONFIG:
944        assert(va == 0);
945        pkt->set(itb->cx_config);
946        break;
947      case ASI_SPARC_ERROR_STATUS_REG:
948        pkt->set((uint64_t)0);
949        break;
950      case ASI_HYP_SCRATCHPAD:
951      case ASI_SCRATCHPAD:
952        pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
953        break;
954      case ASI_IMMU:
955        switch (va) {
956          case 0x0:
957            temp = itb->tag_access;
958            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
959            break;
960          case 0x18:
961            pkt->set(itb->sfsr);
962            break;
963          case 0x30:
964            pkt->set(itb->tag_access);
965            break;
966          default:
967            goto doMmuReadError;
968        }
969        break;
970      case ASI_DMMU:
971        switch (va) {
972          case 0x0:
973            temp = tag_access;
974            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
975            break;
976          case 0x18:
977            pkt->set(sfsr);
978            break;
979          case 0x20:
980            pkt->set(sfar);
981            break;
982          case 0x30:
983            pkt->set(tag_access);
984            break;
985          case 0x80:
986            pkt->set(tc->readMiscReg(MISCREG_MMU_PART_ID));
987            break;
988          default:
989                goto doMmuReadError;
990        }
991        break;
992      case ASI_DMMU_TSB_PS0_PTR_REG:
993        pkt->set(MakeTsbPtr(Ps0,
994            tag_access,
995            c0_tsb_ps0,
996            c0_config,
997            cx_tsb_ps0,
998            cx_config));
999        break;
1000      case ASI_DMMU_TSB_PS1_PTR_REG:
1001        pkt->set(MakeTsbPtr(Ps1,
1002                tag_access,
1003                c0_tsb_ps1,
1004                c0_config,
1005                cx_tsb_ps1,
1006                cx_config));
1007        break;
1008      case ASI_IMMU_TSB_PS0_PTR_REG:
1009          pkt->set(MakeTsbPtr(Ps0,
1010                itb->tag_access,
1011                itb->c0_tsb_ps0,
1012                itb->c0_config,
1013                itb->cx_tsb_ps0,
1014                itb->cx_config));
1015        break;
1016      case ASI_IMMU_TSB_PS1_PTR_REG:
1017          pkt->set(MakeTsbPtr(Ps1,
1018                itb->tag_access,
1019                itb->c0_tsb_ps1,
1020                itb->c0_config,
1021                itb->cx_tsb_ps1,
1022                itb->cx_config));
1023        break;
1024      case ASI_SWVR_INTR_RECEIVE:
1025        pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
1026        break;
1027      case ASI_SWVR_UDB_INTR_R:
1028        temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
1029        tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp);
1030        pkt->set(temp);
1031        break;
1032      default:
1033doMmuReadError:
1034        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1035            (uint32_t)asi, va);
1036    }
1037    pkt->makeAtomicResponse();
1038    return tc->getCpuPtr()->cycles(1);
1039}
1040
1041Tick
1042DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1043{
1044    uint64_t data = gtoh(pkt->get<uint64_t>());
1045    Addr va = pkt->getAddr();
1046    ASI asi = (ASI)pkt->req->getAsi();
1047
1048    Addr ta_insert;
1049    Addr va_insert;
1050    Addr ct_insert;
1051    int part_insert;
1052    int entry_insert = -1;
1053    bool real_insert;
1054    bool ignore;
1055    int part_id;
1056    int ctx_id;
1057    PageTableEntry pte;
1058
1059    DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1060         (uint32_t)asi, va, data);
1061
1062    ITB * itb = tc->getITBPtr();
1063
1064    switch (asi) {
1065      case ASI_LSU_CONTROL_REG:
1066        assert(va == 0);
1067        tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data);
1068        break;
1069      case ASI_MMU:
1070        switch (va) {
1071          case 0x8:
1072            tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data);
1073            break;
1074          case 0x10:
1075            tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data);
1076            break;
1077          default:
1078            goto doMmuWriteError;
1079        }
1080        break;
1081      case ASI_QUEUE:
1082        assert(mbits(data,13,6) == data);
1083        tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
1084                    (va >> 4) - 0x3c, data);
1085        break;
1086      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1087        assert(va == 0);
1088        c0_tsb_ps0 = data;
1089        break;
1090      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1091        assert(va == 0);
1092        c0_tsb_ps1 = data;
1093        break;
1094      case ASI_DMMU_CTXT_ZERO_CONFIG:
1095        assert(va == 0);
1096        c0_config = data;
1097        break;
1098      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1099        assert(va == 0);
1100        itb->c0_tsb_ps0 = data;
1101        break;
1102      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1103        assert(va == 0);
1104        itb->c0_tsb_ps1 = data;
1105        break;
1106      case ASI_IMMU_CTXT_ZERO_CONFIG:
1107        assert(va == 0);
1108        itb->c0_config = data;
1109        break;
1110      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1111        assert(va == 0);
1112        cx_tsb_ps0 = data;
1113        break;
1114      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1115        assert(va == 0);
1116        cx_tsb_ps1 = data;
1117        break;
1118      case ASI_DMMU_CTXT_NONZERO_CONFIG:
1119        assert(va == 0);
1120        cx_config = data;
1121        break;
1122      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1123        assert(va == 0);
1124        itb->cx_tsb_ps0 = data;
1125        break;
1126      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1127        assert(va == 0);
1128        itb->cx_tsb_ps1 = data;
1129        break;
1130      case ASI_IMMU_CTXT_NONZERO_CONFIG:
1131        assert(va == 0);
1132        itb->cx_config = data;
1133        break;
1134      case ASI_SPARC_ERROR_EN_REG:
1135      case ASI_SPARC_ERROR_STATUS_REG:
1136        warn("Ignoring write to SPARC ERROR regsiter\n");
1137        break;
1138      case ASI_HYP_SCRATCHPAD:
1139      case ASI_SCRATCHPAD:
1140        tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1141        break;
1142      case ASI_IMMU:
1143        switch (va) {
1144          case 0x18:
1145            itb->sfsr = data;
1146            break;
1147          case 0x30:
1148            sext<59>(bits(data, 59,0));
1149            itb->tag_access = data;
1150            break;
1151          default:
1152            goto doMmuWriteError;
1153        }
1154        break;
1155      case ASI_ITLB_DATA_ACCESS_REG:
1156        entry_insert = bits(va, 8,3);
1157      case ASI_ITLB_DATA_IN_REG:
1158        assert(entry_insert != -1 || mbits(va,10,9) == va);
1159        ta_insert = itb->tag_access;
1160        va_insert = mbits(ta_insert, 63,13);
1161        ct_insert = mbits(ta_insert, 12,0);
1162        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1163        real_insert = bits(va, 9,9);
1164        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1165                PageTableEntry::sun4u);
1166        tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1167                pte, entry_insert);
1168        break;
1169      case ASI_DTLB_DATA_ACCESS_REG:
1170        entry_insert = bits(va, 8,3);
1171      case ASI_DTLB_DATA_IN_REG:
1172        assert(entry_insert != -1 || mbits(va,10,9) == va);
1173        ta_insert = tag_access;
1174        va_insert = mbits(ta_insert, 63,13);
1175        ct_insert = mbits(ta_insert, 12,0);
1176        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1177        real_insert = bits(va, 9,9);
1178        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1179                PageTableEntry::sun4u);
1180        insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1181        break;
1182      case ASI_IMMU_DEMAP:
1183        ignore = false;
1184        ctx_id = -1;
1185        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1186        switch (bits(va,5,4)) {
1187          case 0:
1188            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1189            break;
1190          case 1:
1191            ignore = true;
1192            break;
1193          case 3:
1194            ctx_id = 0;
1195            break;
1196          default:
1197            ignore = true;
1198        }
1199
1200        switch(bits(va,7,6)) {
1201          case 0: // demap page
1202            if (!ignore)
1203                tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1204                        bits(va,9,9), ctx_id);
1205            break;
1206          case 1: //demap context
1207            if (!ignore)
1208                tc->getITBPtr()->demapContext(part_id, ctx_id);
1209            break;
1210          case 2:
1211            tc->getITBPtr()->demapAll(part_id);
1212            break;
1213          default:
1214            panic("Invalid type for IMMU demap\n");
1215        }
1216        break;
1217      case ASI_DMMU:
1218        switch (va) {
1219          case 0x18:
1220            sfsr = data;
1221            break;
1222          case 0x30:
1223            sext<59>(bits(data, 59,0));
1224            tag_access = data;
1225            break;
1226          case 0x80:
1227            tc->setMiscReg(MISCREG_MMU_PART_ID, data);
1228            break;
1229          default:
1230            goto doMmuWriteError;
1231        }
1232        break;
1233      case ASI_DMMU_DEMAP:
1234        ignore = false;
1235        ctx_id = -1;
1236        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1237        switch (bits(va,5,4)) {
1238          case 0:
1239            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1240            break;
1241          case 1:
1242            ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
1243            break;
1244          case 3:
1245            ctx_id = 0;
1246            break;
1247          default:
1248            ignore = true;
1249        }
1250
1251        switch(bits(va,7,6)) {
1252          case 0: // demap page
1253            if (!ignore)
1254                demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1255            break;
1256          case 1: //demap context
1257            if (!ignore)
1258                demapContext(part_id, ctx_id);
1259            break;
1260          case 2:
1261            demapAll(part_id);
1262            break;
1263          default:
1264            panic("Invalid type for IMMU demap\n");
1265        }
1266        break;
1267       case ASI_SWVR_INTR_RECEIVE:
1268        int msb;
1269        // clear all the interrupts that aren't set in the write
1270        while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) {
1271            msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data);
1272            tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb);
1273        }
1274        break;
1275      case ASI_SWVR_UDB_INTR_W:
1276            tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
1277            post_interrupt(bits(data,5,0),0);
1278        break;
1279 default:
1280doMmuWriteError:
1281        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1282            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1283    }
1284    pkt->makeAtomicResponse();
1285    return tc->getCpuPtr()->cycles(1);
1286}
1287
1288#endif
1289
1290void
1291DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
1292{
1293    uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0);
1294    ITB * itb = tc->getITBPtr();
1295    ptrs[0] = MakeTsbPtr(Ps0, tag_access,
1296                c0_tsb_ps0,
1297                c0_config,
1298                cx_tsb_ps0,
1299                cx_config);
1300    ptrs[1] = MakeTsbPtr(Ps1, tag_access,
1301                c0_tsb_ps1,
1302                c0_config,
1303                cx_tsb_ps1,
1304                cx_config);
1305    ptrs[2] = MakeTsbPtr(Ps0, tag_access,
1306                itb->c0_tsb_ps0,
1307                itb->c0_config,
1308                itb->cx_tsb_ps0,
1309                itb->cx_config);
1310    ptrs[3] = MakeTsbPtr(Ps1, tag_access,
1311                itb->c0_tsb_ps1,
1312                itb->c0_config,
1313                itb->cx_tsb_ps1,
1314                itb->cx_config);
1315}
1316
1317
1318
1319
1320
1321uint64_t
1322DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
1323        uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
1324{
1325    uint64_t tsb;
1326    uint64_t config;
1327
1328    if (bits(tag_access, 12,0) == 0) {
1329        tsb = c0_tsb;
1330        config = c0_config;
1331    } else {
1332        tsb = cX_tsb;
1333        config = cX_config;
1334    }
1335
1336    uint64_t ptr = mbits(tsb,63,13);
1337    bool split = bits(tsb,12,12);
1338    int tsb_size = bits(tsb,3,0);
1339    int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8);
1340
1341    if (ps == Ps1  && split)
1342        ptr |= ULL(1) << (13 + tsb_size);
1343    ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4);
1344
1345    return ptr;
1346}
1347
1348
1349void
1350TLB::serialize(std::ostream &os)
1351{
1352    SERIALIZE_SCALAR(size);
1353    SERIALIZE_SCALAR(usedEntries);
1354    SERIALIZE_SCALAR(lastReplaced);
1355
1356    // convert the pointer based free list into an index based one
1357    int *free_list = (int*)malloc(sizeof(int) * size);
1358    int cntr = 0;
1359    std::list<TlbEntry*>::iterator i;
1360    i = freeList.begin();
1361    while (i != freeList.end()) {
1362        free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry);
1363        i++;
1364    }
1365    SERIALIZE_SCALAR(cntr);
1366    SERIALIZE_ARRAY(free_list,  cntr);
1367
1368    for (int x = 0; x < size; x++) {
1369        nameOut(os, csprintf("%s.PTE%d", name(), x));
1370        tlb[x].serialize(os);
1371    }
1372
1373    SERIALIZE_SCALAR(c0_tsb_ps0);
1374    SERIALIZE_SCALAR(c0_tsb_ps1);
1375    SERIALIZE_SCALAR(c0_config);
1376    SERIALIZE_SCALAR(cx_tsb_ps0);
1377    SERIALIZE_SCALAR(cx_tsb_ps1);
1378    SERIALIZE_SCALAR(cx_config);
1379    SERIALIZE_SCALAR(sfsr);
1380    SERIALIZE_SCALAR(tag_access);
1381}
1382
1383void
1384TLB::unserialize(Checkpoint *cp, const std::string &section)
1385{
1386    int oldSize;
1387
1388    paramIn(cp, section, "size", oldSize);
1389    if (oldSize != size)
1390        panic("Don't support unserializing different sized TLBs\n");
1391    UNSERIALIZE_SCALAR(usedEntries);
1392    UNSERIALIZE_SCALAR(lastReplaced);
1393
1394    int cntr;
1395    UNSERIALIZE_SCALAR(cntr);
1396
1397    int *free_list = (int*)malloc(sizeof(int) * cntr);
1398    freeList.clear();
1399    UNSERIALIZE_ARRAY(free_list,  cntr);
1400    for (int x = 0; x < cntr; x++)
1401        freeList.push_back(&tlb[free_list[x]]);
1402
1403    lookupTable.clear();
1404    for (int x = 0; x < size; x++) {
1405        tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
1406        if (tlb[x].valid)
1407            lookupTable.insert(tlb[x].range, &tlb[x]);
1408
1409    }
1410
1411    UNSERIALIZE_SCALAR(c0_tsb_ps0);
1412    UNSERIALIZE_SCALAR(c0_tsb_ps1);
1413    UNSERIALIZE_SCALAR(c0_config);
1414    UNSERIALIZE_SCALAR(cx_tsb_ps0);
1415    UNSERIALIZE_SCALAR(cx_tsb_ps1);
1416    UNSERIALIZE_SCALAR(cx_config);
1417    UNSERIALIZE_SCALAR(sfsr);
1418    UNSERIALIZE_SCALAR(tag_access);
1419}
1420
1421void
1422DTB::serialize(std::ostream &os)
1423{
1424    TLB::serialize(os);
1425    SERIALIZE_SCALAR(sfar);
1426}
1427
1428void
1429DTB::unserialize(Checkpoint *cp, const std::string &section)
1430{
1431    TLB::unserialize(cp, section);
1432    UNSERIALIZE_SCALAR(sfar);
1433}
1434
1435/* end namespace SparcISA */ }
1436
1437SparcISA::ITB *
1438SparcITBParams::create()
1439{
1440    return new SparcISA::ITB(name, size);
1441}
1442
1443SparcISA::DTB *
1444SparcDTBParams::create()
1445{
1446    return new SparcISA::DTB(name, size);
1447}
1448