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