tlb.cc revision 4990
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            return new FastInstructionAccessMMUMiss;
539    }
540
541    // were not priviledged accesing priv page
542    if (!priv && e->pte.priv()) {
543        writeTagAccess(vaddr, context);
544        writeSfsr(false, ct, false, PrivViolation, asi);
545        return new InstructionAccessException;
546    }
547
548    // cache translation date for next translation
549    cacheValid = true;
550    cacheState = tlbdata;
551    cacheEntry = e;
552
553    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
554                  vaddr & e->pte.size()-1 );
555    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
556    return NoFault;
557}
558
559
560
561Fault
562DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
563{
564    /* @todo this could really use some profiling and fixing to make it faster! */
565    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
566    Addr vaddr = req->getVaddr();
567    Addr size = req->getSize();
568    ASI asi;
569    asi = (ASI)req->getAsi();
570    bool implicit = false;
571    bool hpriv = bits(tlbdata,0,0);
572
573    DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
574            vaddr, size, asi);
575
576    if (lookupTable.size() != 64 - freeList.size())
577       panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(),
578               freeList.size());
579    if (asi == ASI_IMPLICIT)
580        implicit = true;
581
582    if (hpriv && implicit) {
583        req->setPaddr(vaddr & PAddrImplMask);
584        return NoFault;
585    }
586
587    // Be fast if we can!
588    if (cacheValid &&  cacheState == tlbdata) {
589
590
591
592        if (cacheEntry[0]) {
593            TlbEntry *ce = cacheEntry[0];
594            Addr ce_va = ce->range.va;
595            if (cacheAsi[0] == asi &&
596                ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
597                (!write || ce->pte.writable())) {
598                    req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
599                    if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
600                        req->setFlags(req->getFlags() | UNCACHEABLE);
601                    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
602                    return NoFault;
603            } // if matched
604        } // if cache entry valid
605        if (cacheEntry[1]) {
606            TlbEntry *ce = cacheEntry[1];
607            Addr ce_va = ce->range.va;
608            if (cacheAsi[1] == asi &&
609                ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
610                (!write || ce->pte.writable())) {
611                    req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
612                    if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
613                        req->setFlags(req->getFlags() | UNCACHEABLE);
614                    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
615                    return NoFault;
616            } // if matched
617        } // if cache entry valid
618     }
619
620    bool red = bits(tlbdata,1,1);
621    bool priv = bits(tlbdata,2,2);
622    bool addr_mask = bits(tlbdata,3,3);
623    bool lsu_dm = bits(tlbdata,5,5);
624
625    int part_id = bits(tlbdata,15,8);
626    int tl = bits(tlbdata,18,16);
627    int pri_context = bits(tlbdata,47,32);
628    int sec_context = bits(tlbdata,63,48);
629
630    bool real = false;
631    ContextType ct = Primary;
632    int context = 0;
633
634    TlbEntry *e;
635
636    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
637           priv, hpriv, red, lsu_dm, part_id);
638
639    if (implicit) {
640        if (tl > 0) {
641            asi = ASI_N;
642            ct = Nucleus;
643            context = 0;
644        } else {
645            asi = ASI_P;
646            ct = Primary;
647            context = pri_context;
648        }
649    } else {
650        // We need to check for priv level/asi priv
651        if (!priv && !hpriv && !AsiIsUnPriv(asi)) {
652            // It appears that context should be Nucleus in these cases?
653            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
654            return new PrivilegedAction;
655        }
656
657        if (!hpriv && AsiIsHPriv(asi)) {
658            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
659            return new DataAccessException;
660        }
661
662        if (AsiIsPrimary(asi)) {
663            context = pri_context;
664            ct = Primary;
665        } else if (AsiIsSecondary(asi)) {
666            context = sec_context;
667            ct = Secondary;
668        } else if (AsiIsNucleus(asi)) {
669            ct = Nucleus;
670            context = 0;
671        } else {  // ????
672            ct = Primary;
673            context = pri_context;
674        }
675    }
676
677    if (!implicit && asi != ASI_P && asi != ASI_S) {
678        if (AsiIsLittle(asi))
679            panic("Little Endian ASIs not supported\n");
680
681        //XXX It's unclear from looking at the documentation how a no fault
682        //load differs from a regular one, other than what happens concerning
683        //nfo and e bits in the TTE
684//        if (AsiIsNoFault(asi))
685//            panic("No Fault ASIs not supported\n");
686
687        if (AsiIsPartialStore(asi))
688            panic("Partial Store ASIs not supported\n");
689
690        if (AsiIsCmt(asi))
691            panic("Cmt ASI registers not implmented\n");
692
693        if (AsiIsInterrupt(asi))
694            goto handleIntRegAccess;
695        if (AsiIsMmu(asi))
696            goto handleMmuRegAccess;
697        if (AsiIsScratchPad(asi))
698            goto handleScratchRegAccess;
699        if (AsiIsQueue(asi))
700            goto handleQueueRegAccess;
701        if (AsiIsSparcError(asi))
702            goto handleSparcErrorRegAccess;
703
704        if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) &&
705                !AsiIsTwin(asi) && !AsiIsBlock(asi) && !AsiIsNoFault(asi))
706            panic("Accessing ASI %#X. Should we?\n", asi);
707    }
708
709    // If the asi is unaligned trap
710    if (vaddr & size-1) {
711        writeSfsr(vaddr, false, ct, false, OtherFault, asi);
712        return new MemAddressNotAligned;
713    }
714
715    if (addr_mask)
716        vaddr = vaddr & VAddrAMask;
717
718    if (!validVirtualAddress(vaddr, addr_mask)) {
719        writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi);
720        return new DataAccessException;
721    }
722
723
724    if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {
725        real = true;
726        context = 0;
727    };
728
729    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
730        req->setPaddr(vaddr & PAddrImplMask);
731        return NoFault;
732    }
733
734    e = lookup(vaddr, part_id, real, context);
735
736    if (e == NULL || !e->valid) {
737        writeTagAccess(vaddr, context);
738        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
739        if (real)
740            return new DataRealTranslationMiss;
741        else
742            return new FastDataAccessMMUMiss;
743
744    }
745
746    if (!priv && e->pte.priv()) {
747        writeTagAccess(vaddr, context);
748        writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
749        return new DataAccessException;
750    }
751
752    if (write && !e->pte.writable()) {
753        writeTagAccess(vaddr, context);
754        writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
755        return new FastDataAccessProtection;
756    }
757
758    if (e->pte.nofault() && !AsiIsNoFault(asi)) {
759        writeTagAccess(vaddr, context);
760        writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
761        return new DataAccessException;
762    }
763
764    if (e->pte.sideffect() && AsiIsNoFault(asi)) {
765        writeTagAccess(vaddr, context);
766        writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi);
767        return new DataAccessException;
768    }
769
770
771    if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
772        req->setFlags(req->getFlags() | UNCACHEABLE);
773
774    // cache translation date for next translation
775    cacheState = tlbdata;
776    if (!cacheValid) {
777        cacheEntry[1] = NULL;
778        cacheEntry[0] = NULL;
779    }
780
781    if (cacheEntry[0] != e && cacheEntry[1] != e) {
782        cacheEntry[1] = cacheEntry[0];
783        cacheEntry[0] = e;
784        cacheAsi[1] = cacheAsi[0];
785        cacheAsi[0] = asi;
786        if (implicit)
787            cacheAsi[0] = (ASI)0;
788    }
789    cacheValid = true;
790    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
791                  vaddr & e->pte.size()-1);
792    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
793    return NoFault;
794
795    /** Normal flow ends here. */
796handleIntRegAccess:
797    if (!hpriv) {
798        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
799        if (priv)
800            return new DataAccessException;
801         else
802            return new PrivilegedAction;
803    }
804
805    if (asi == ASI_SWVR_UDB_INTR_W && !write ||
806                    asi == ASI_SWVR_UDB_INTR_R && write) {
807        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
808        return new DataAccessException;
809    }
810
811    goto regAccessOk;
812
813
814handleScratchRegAccess:
815    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
816        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
817        return new DataAccessException;
818    }
819    goto regAccessOk;
820
821handleQueueRegAccess:
822    if (!priv  && !hpriv) {
823        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
824        return new PrivilegedAction;
825    }
826    if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
827        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
828        return new DataAccessException;
829    }
830    goto regAccessOk;
831
832handleSparcErrorRegAccess:
833    if (!hpriv) {
834        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
835        if (priv)
836            return new DataAccessException;
837         else
838            return new PrivilegedAction;
839    }
840    goto regAccessOk;
841
842
843regAccessOk:
844handleMmuRegAccess:
845    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
846    req->setMmapedIpr(true);
847    req->setPaddr(req->getVaddr());
848    return NoFault;
849};
850
851Tick
852DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
853{
854    Addr va = pkt->getAddr();
855    ASI asi = (ASI)pkt->req->getAsi();
856    uint64_t temp;
857
858    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
859         (uint32_t)pkt->req->getAsi(), pkt->getAddr());
860
861    ITB * itb = tc->getITBPtr();
862
863    switch (asi) {
864      case ASI_LSU_CONTROL_REG:
865        assert(va == 0);
866        pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL));
867        break;
868      case ASI_MMU:
869        switch (va) {
870          case 0x8:
871            pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT));
872            break;
873          case 0x10:
874            pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT));
875            break;
876          default:
877            goto doMmuReadError;
878        }
879        break;
880      case ASI_QUEUE:
881        pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
882                    (va >> 4) - 0x3c));
883        break;
884      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
885        assert(va == 0);
886        pkt->set(c0_tsb_ps0);
887        break;
888      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
889        assert(va == 0);
890        pkt->set(c0_tsb_ps1);
891        break;
892      case ASI_DMMU_CTXT_ZERO_CONFIG:
893        assert(va == 0);
894        pkt->set(c0_config);
895        break;
896      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
897        assert(va == 0);
898        pkt->set(itb->c0_tsb_ps0);
899        break;
900      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
901        assert(va == 0);
902        pkt->set(itb->c0_tsb_ps1);
903        break;
904      case ASI_IMMU_CTXT_ZERO_CONFIG:
905        assert(va == 0);
906        pkt->set(itb->c0_config);
907        break;
908      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
909        assert(va == 0);
910        pkt->set(cx_tsb_ps0);
911        break;
912      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
913        assert(va == 0);
914        pkt->set(cx_tsb_ps1);
915        break;
916      case ASI_DMMU_CTXT_NONZERO_CONFIG:
917        assert(va == 0);
918        pkt->set(cx_config);
919        break;
920      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
921        assert(va == 0);
922        pkt->set(itb->cx_tsb_ps0);
923        break;
924      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
925        assert(va == 0);
926        pkt->set(itb->cx_tsb_ps1);
927        break;
928      case ASI_IMMU_CTXT_NONZERO_CONFIG:
929        assert(va == 0);
930        pkt->set(itb->cx_config);
931        break;
932      case ASI_SPARC_ERROR_STATUS_REG:
933        pkt->set((uint64_t)0);
934        break;
935      case ASI_HYP_SCRATCHPAD:
936      case ASI_SCRATCHPAD:
937        pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
938        break;
939      case ASI_IMMU:
940        switch (va) {
941          case 0x0:
942            temp = itb->tag_access;
943            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
944            break;
945          case 0x18:
946            pkt->set(itb->sfsr);
947            break;
948          case 0x30:
949            pkt->set(itb->tag_access);
950            break;
951          default:
952            goto doMmuReadError;
953        }
954        break;
955      case ASI_DMMU:
956        switch (va) {
957          case 0x0:
958            temp = tag_access;
959            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
960            break;
961          case 0x18:
962            pkt->set(sfsr);
963            break;
964          case 0x20:
965            pkt->set(sfar);
966            break;
967          case 0x30:
968            pkt->set(tag_access);
969            break;
970          case 0x80:
971            pkt->set(tc->readMiscReg(MISCREG_MMU_PART_ID));
972            break;
973          default:
974                goto doMmuReadError;
975        }
976        break;
977      case ASI_DMMU_TSB_PS0_PTR_REG:
978        pkt->set(MakeTsbPtr(Ps0,
979            tag_access,
980            c0_tsb_ps0,
981            c0_config,
982            cx_tsb_ps0,
983            cx_config));
984        break;
985      case ASI_DMMU_TSB_PS1_PTR_REG:
986        pkt->set(MakeTsbPtr(Ps1,
987                tag_access,
988                c0_tsb_ps1,
989                c0_config,
990                cx_tsb_ps1,
991                cx_config));
992        break;
993      case ASI_IMMU_TSB_PS0_PTR_REG:
994          pkt->set(MakeTsbPtr(Ps0,
995                itb->tag_access,
996                itb->c0_tsb_ps0,
997                itb->c0_config,
998                itb->cx_tsb_ps0,
999                itb->cx_config));
1000        break;
1001      case ASI_IMMU_TSB_PS1_PTR_REG:
1002          pkt->set(MakeTsbPtr(Ps1,
1003                itb->tag_access,
1004                itb->c0_tsb_ps1,
1005                itb->c0_config,
1006                itb->cx_tsb_ps1,
1007                itb->cx_config));
1008        break;
1009      case ASI_SWVR_INTR_RECEIVE:
1010        pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
1011        break;
1012      case ASI_SWVR_UDB_INTR_R:
1013        temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
1014        tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp);
1015        pkt->set(temp);
1016        break;
1017      default:
1018doMmuReadError:
1019        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1020            (uint32_t)asi, va);
1021    }
1022    pkt->makeAtomicResponse();
1023    return tc->getCpuPtr()->cycles(1);
1024}
1025
1026Tick
1027DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1028{
1029    uint64_t data = gtoh(pkt->get<uint64_t>());
1030    Addr va = pkt->getAddr();
1031    ASI asi = (ASI)pkt->req->getAsi();
1032
1033    Addr ta_insert;
1034    Addr va_insert;
1035    Addr ct_insert;
1036    int part_insert;
1037    int entry_insert = -1;
1038    bool real_insert;
1039    bool ignore;
1040    int part_id;
1041    int ctx_id;
1042    PageTableEntry pte;
1043
1044    DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1045         (uint32_t)asi, va, data);
1046
1047    ITB * itb = tc->getITBPtr();
1048
1049    switch (asi) {
1050      case ASI_LSU_CONTROL_REG:
1051        assert(va == 0);
1052        tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data);
1053        break;
1054      case ASI_MMU:
1055        switch (va) {
1056          case 0x8:
1057            tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data);
1058            break;
1059          case 0x10:
1060            tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data);
1061            break;
1062          default:
1063            goto doMmuWriteError;
1064        }
1065        break;
1066      case ASI_QUEUE:
1067        assert(mbits(data,13,6) == data);
1068        tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
1069                    (va >> 4) - 0x3c, data);
1070        break;
1071      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1072        assert(va == 0);
1073        c0_tsb_ps0 = data;
1074        break;
1075      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1076        assert(va == 0);
1077        c0_tsb_ps1 = data;
1078        break;
1079      case ASI_DMMU_CTXT_ZERO_CONFIG:
1080        assert(va == 0);
1081        c0_config = data;
1082        break;
1083      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1084        assert(va == 0);
1085        itb->c0_tsb_ps0 = data;
1086        break;
1087      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1088        assert(va == 0);
1089        itb->c0_tsb_ps1 = data;
1090        break;
1091      case ASI_IMMU_CTXT_ZERO_CONFIG:
1092        assert(va == 0);
1093        itb->c0_config = data;
1094        break;
1095      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1096        assert(va == 0);
1097        cx_tsb_ps0 = data;
1098        break;
1099      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1100        assert(va == 0);
1101        cx_tsb_ps1 = data;
1102        break;
1103      case ASI_DMMU_CTXT_NONZERO_CONFIG:
1104        assert(va == 0);
1105        cx_config = data;
1106        break;
1107      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1108        assert(va == 0);
1109        itb->cx_tsb_ps0 = data;
1110        break;
1111      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1112        assert(va == 0);
1113        itb->cx_tsb_ps1 = data;
1114        break;
1115      case ASI_IMMU_CTXT_NONZERO_CONFIG:
1116        assert(va == 0);
1117        itb->cx_config = data;
1118        break;
1119      case ASI_SPARC_ERROR_EN_REG:
1120      case ASI_SPARC_ERROR_STATUS_REG:
1121        warn("Ignoring write to SPARC ERROR regsiter\n");
1122        break;
1123      case ASI_HYP_SCRATCHPAD:
1124      case ASI_SCRATCHPAD:
1125        tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1126        break;
1127      case ASI_IMMU:
1128        switch (va) {
1129          case 0x18:
1130            itb->sfsr = data;
1131            break;
1132          case 0x30:
1133            sext<59>(bits(data, 59,0));
1134            itb->tag_access = data;
1135            break;
1136          default:
1137            goto doMmuWriteError;
1138        }
1139        break;
1140      case ASI_ITLB_DATA_ACCESS_REG:
1141        entry_insert = bits(va, 8,3);
1142      case ASI_ITLB_DATA_IN_REG:
1143        assert(entry_insert != -1 || mbits(va,10,9) == va);
1144        ta_insert = itb->tag_access;
1145        va_insert = mbits(ta_insert, 63,13);
1146        ct_insert = mbits(ta_insert, 12,0);
1147        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1148        real_insert = bits(va, 9,9);
1149        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1150                PageTableEntry::sun4u);
1151        tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1152                pte, entry_insert);
1153        break;
1154      case ASI_DTLB_DATA_ACCESS_REG:
1155        entry_insert = bits(va, 8,3);
1156      case ASI_DTLB_DATA_IN_REG:
1157        assert(entry_insert != -1 || mbits(va,10,9) == va);
1158        ta_insert = tag_access;
1159        va_insert = mbits(ta_insert, 63,13);
1160        ct_insert = mbits(ta_insert, 12,0);
1161        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1162        real_insert = bits(va, 9,9);
1163        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1164                PageTableEntry::sun4u);
1165        insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1166        break;
1167      case ASI_IMMU_DEMAP:
1168        ignore = false;
1169        ctx_id = -1;
1170        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1171        switch (bits(va,5,4)) {
1172          case 0:
1173            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1174            break;
1175          case 1:
1176            ignore = true;
1177            break;
1178          case 3:
1179            ctx_id = 0;
1180            break;
1181          default:
1182            ignore = true;
1183        }
1184
1185        switch(bits(va,7,6)) {
1186          case 0: // demap page
1187            if (!ignore)
1188                tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1189                        bits(va,9,9), ctx_id);
1190            break;
1191          case 1: //demap context
1192            if (!ignore)
1193                tc->getITBPtr()->demapContext(part_id, ctx_id);
1194            break;
1195          case 2:
1196            tc->getITBPtr()->demapAll(part_id);
1197            break;
1198          default:
1199            panic("Invalid type for IMMU demap\n");
1200        }
1201        break;
1202      case ASI_DMMU:
1203        switch (va) {
1204          case 0x18:
1205            sfsr = data;
1206            break;
1207          case 0x30:
1208            sext<59>(bits(data, 59,0));
1209            tag_access = data;
1210            break;
1211          case 0x80:
1212            tc->setMiscReg(MISCREG_MMU_PART_ID, data);
1213            break;
1214          default:
1215            goto doMmuWriteError;
1216        }
1217        break;
1218      case ASI_DMMU_DEMAP:
1219        ignore = false;
1220        ctx_id = -1;
1221        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1222        switch (bits(va,5,4)) {
1223          case 0:
1224            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1225            break;
1226          case 1:
1227            ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
1228            break;
1229          case 3:
1230            ctx_id = 0;
1231            break;
1232          default:
1233            ignore = true;
1234        }
1235
1236        switch(bits(va,7,6)) {
1237          case 0: // demap page
1238            if (!ignore)
1239                demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1240            break;
1241          case 1: //demap context
1242            if (!ignore)
1243                demapContext(part_id, ctx_id);
1244            break;
1245          case 2:
1246            demapAll(part_id);
1247            break;
1248          default:
1249            panic("Invalid type for IMMU demap\n");
1250        }
1251        break;
1252       case ASI_SWVR_INTR_RECEIVE:
1253        int msb;
1254        // clear all the interrupts that aren't set in the write
1255        while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) {
1256            msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data);
1257            tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb);
1258        }
1259        break;
1260      case ASI_SWVR_UDB_INTR_W:
1261            tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
1262            post_interrupt(bits(data,5,0),0);
1263        break;
1264 default:
1265doMmuWriteError:
1266        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1267            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1268    }
1269    pkt->makeAtomicResponse();
1270    return tc->getCpuPtr()->cycles(1);
1271}
1272
1273void
1274DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
1275{
1276    uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0);
1277    ITB * itb = tc->getITBPtr();
1278    ptrs[0] = MakeTsbPtr(Ps0, tag_access,
1279                c0_tsb_ps0,
1280                c0_config,
1281                cx_tsb_ps0,
1282                cx_config);
1283    ptrs[1] = MakeTsbPtr(Ps1, tag_access,
1284                c0_tsb_ps1,
1285                c0_config,
1286                cx_tsb_ps1,
1287                cx_config);
1288    ptrs[2] = MakeTsbPtr(Ps0, tag_access,
1289                itb->c0_tsb_ps0,
1290                itb->c0_config,
1291                itb->cx_tsb_ps0,
1292                itb->cx_config);
1293    ptrs[3] = MakeTsbPtr(Ps1, tag_access,
1294                itb->c0_tsb_ps1,
1295                itb->c0_config,
1296                itb->cx_tsb_ps1,
1297                itb->cx_config);
1298}
1299
1300
1301
1302
1303
1304uint64_t
1305DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
1306        uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
1307{
1308    uint64_t tsb;
1309    uint64_t config;
1310
1311    if (bits(tag_access, 12,0) == 0) {
1312        tsb = c0_tsb;
1313        config = c0_config;
1314    } else {
1315        tsb = cX_tsb;
1316        config = cX_config;
1317    }
1318
1319    uint64_t ptr = mbits(tsb,63,13);
1320    bool split = bits(tsb,12,12);
1321    int tsb_size = bits(tsb,3,0);
1322    int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8);
1323
1324    if (ps == Ps1  && split)
1325        ptr |= ULL(1) << (13 + tsb_size);
1326    ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4);
1327
1328    return ptr;
1329}
1330
1331
1332void
1333TLB::serialize(std::ostream &os)
1334{
1335    SERIALIZE_SCALAR(size);
1336    SERIALIZE_SCALAR(usedEntries);
1337    SERIALIZE_SCALAR(lastReplaced);
1338
1339    // convert the pointer based free list into an index based one
1340    int *free_list = (int*)malloc(sizeof(int) * size);
1341    int cntr = 0;
1342    std::list<TlbEntry*>::iterator i;
1343    i = freeList.begin();
1344    while (i != freeList.end()) {
1345        free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry);
1346        i++;
1347    }
1348    SERIALIZE_SCALAR(cntr);
1349    SERIALIZE_ARRAY(free_list,  cntr);
1350
1351    for (int x = 0; x < size; x++) {
1352        nameOut(os, csprintf("%s.PTE%d", name(), x));
1353        tlb[x].serialize(os);
1354    }
1355
1356    SERIALIZE_SCALAR(c0_tsb_ps0);
1357    SERIALIZE_SCALAR(c0_tsb_ps1);
1358    SERIALIZE_SCALAR(c0_config);
1359    SERIALIZE_SCALAR(cx_tsb_ps0);
1360    SERIALIZE_SCALAR(cx_tsb_ps1);
1361    SERIALIZE_SCALAR(cx_config);
1362    SERIALIZE_SCALAR(sfsr);
1363    SERIALIZE_SCALAR(tag_access);
1364}
1365
1366void
1367TLB::unserialize(Checkpoint *cp, const std::string &section)
1368{
1369    int oldSize;
1370
1371    paramIn(cp, section, "size", oldSize);
1372    if (oldSize != size)
1373        panic("Don't support unserializing different sized TLBs\n");
1374    UNSERIALIZE_SCALAR(usedEntries);
1375    UNSERIALIZE_SCALAR(lastReplaced);
1376
1377    int cntr;
1378    UNSERIALIZE_SCALAR(cntr);
1379
1380    int *free_list = (int*)malloc(sizeof(int) * cntr);
1381    freeList.clear();
1382    UNSERIALIZE_ARRAY(free_list,  cntr);
1383    for (int x = 0; x < cntr; x++)
1384        freeList.push_back(&tlb[free_list[x]]);
1385
1386    lookupTable.clear();
1387    for (int x = 0; x < size; x++) {
1388        tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
1389        if (tlb[x].valid)
1390            lookupTable.insert(tlb[x].range, &tlb[x]);
1391
1392    }
1393
1394    UNSERIALIZE_SCALAR(c0_tsb_ps0);
1395    UNSERIALIZE_SCALAR(c0_tsb_ps1);
1396    UNSERIALIZE_SCALAR(c0_config);
1397    UNSERIALIZE_SCALAR(cx_tsb_ps0);
1398    UNSERIALIZE_SCALAR(cx_tsb_ps1);
1399    UNSERIALIZE_SCALAR(cx_config);
1400    UNSERIALIZE_SCALAR(sfsr);
1401    UNSERIALIZE_SCALAR(tag_access);
1402}
1403
1404void
1405DTB::serialize(std::ostream &os)
1406{
1407    TLB::serialize(os);
1408    SERIALIZE_SCALAR(sfar);
1409}
1410
1411void
1412DTB::unserialize(Checkpoint *cp, const std::string &section)
1413{
1414    TLB::unserialize(cp, section);
1415    UNSERIALIZE_SCALAR(sfar);
1416}
1417
1418/* end namespace SparcISA */ }
1419
1420SparcISA::ITB *
1421SparcITBParams::create()
1422{
1423    return new SparcISA::ITB(name, size);
1424}
1425
1426SparcISA::DTB *
1427SparcDTBParams::create()
1428{
1429    return new SparcISA::DTB(name, size);
1430}
1431