tlb.cc revision 5736:426510e758ad
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(Request::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(Request::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(Request::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        {
1012            SparcISA::Interrupts * interrupts =
1013                dynamic_cast<SparcISA::Interrupts *>(
1014                        tc->getCpuPtr()->getInterruptController());
1015            pkt->set(interrupts->get_vec(IT_INT_VEC));
1016        }
1017        break;
1018      case ASI_SWVR_UDB_INTR_R:
1019        {
1020            SparcISA::Interrupts * interrupts =
1021                dynamic_cast<SparcISA::Interrupts *>(
1022                        tc->getCpuPtr()->getInterruptController());
1023            temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
1024            tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp);
1025            pkt->set(temp);
1026        }
1027        break;
1028      default:
1029doMmuReadError:
1030        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1031            (uint32_t)asi, va);
1032    }
1033    pkt->makeAtomicResponse();
1034    return tc->getCpuPtr()->ticks(1);
1035}
1036
1037Tick
1038DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1039{
1040    uint64_t data = gtoh(pkt->get<uint64_t>());
1041    Addr va = pkt->getAddr();
1042    ASI asi = (ASI)pkt->req->getAsi();
1043
1044    Addr ta_insert;
1045    Addr va_insert;
1046    Addr ct_insert;
1047    int part_insert;
1048    int entry_insert = -1;
1049    bool real_insert;
1050    bool ignore;
1051    int part_id;
1052    int ctx_id;
1053    PageTableEntry pte;
1054
1055    DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1056         (uint32_t)asi, va, data);
1057
1058    ITB *itb = tc->getITBPtr();
1059
1060    switch (asi) {
1061      case ASI_LSU_CONTROL_REG:
1062        assert(va == 0);
1063        tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data);
1064        break;
1065      case ASI_MMU:
1066        switch (va) {
1067          case 0x8:
1068            tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data);
1069            break;
1070          case 0x10:
1071            tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data);
1072            break;
1073          default:
1074            goto doMmuWriteError;
1075        }
1076        break;
1077      case ASI_QUEUE:
1078        assert(mbits(data,13,6) == data);
1079        tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
1080                    (va >> 4) - 0x3c, data);
1081        break;
1082      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1083        assert(va == 0);
1084        c0_tsb_ps0 = data;
1085        break;
1086      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1087        assert(va == 0);
1088        c0_tsb_ps1 = data;
1089        break;
1090      case ASI_DMMU_CTXT_ZERO_CONFIG:
1091        assert(va == 0);
1092        c0_config = data;
1093        break;
1094      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1095        assert(va == 0);
1096        itb->c0_tsb_ps0 = data;
1097        break;
1098      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1099        assert(va == 0);
1100        itb->c0_tsb_ps1 = data;
1101        break;
1102      case ASI_IMMU_CTXT_ZERO_CONFIG:
1103        assert(va == 0);
1104        itb->c0_config = data;
1105        break;
1106      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1107        assert(va == 0);
1108        cx_tsb_ps0 = data;
1109        break;
1110      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1111        assert(va == 0);
1112        cx_tsb_ps1 = data;
1113        break;
1114      case ASI_DMMU_CTXT_NONZERO_CONFIG:
1115        assert(va == 0);
1116        cx_config = data;
1117        break;
1118      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1119        assert(va == 0);
1120        itb->cx_tsb_ps0 = data;
1121        break;
1122      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1123        assert(va == 0);
1124        itb->cx_tsb_ps1 = data;
1125        break;
1126      case ASI_IMMU_CTXT_NONZERO_CONFIG:
1127        assert(va == 0);
1128        itb->cx_config = data;
1129        break;
1130      case ASI_SPARC_ERROR_EN_REG:
1131      case ASI_SPARC_ERROR_STATUS_REG:
1132        warn("Ignoring write to SPARC ERROR regsiter\n");
1133        break;
1134      case ASI_HYP_SCRATCHPAD:
1135      case ASI_SCRATCHPAD:
1136        tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1137        break;
1138      case ASI_IMMU:
1139        switch (va) {
1140          case 0x18:
1141            itb->sfsr = data;
1142            break;
1143          case 0x30:
1144            sext<59>(bits(data, 59,0));
1145            itb->tag_access = data;
1146            break;
1147          default:
1148            goto doMmuWriteError;
1149        }
1150        break;
1151      case ASI_ITLB_DATA_ACCESS_REG:
1152        entry_insert = bits(va, 8,3);
1153      case ASI_ITLB_DATA_IN_REG:
1154        assert(entry_insert != -1 || mbits(va,10,9) == va);
1155        ta_insert = itb->tag_access;
1156        va_insert = mbits(ta_insert, 63,13);
1157        ct_insert = mbits(ta_insert, 12,0);
1158        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1159        real_insert = bits(va, 9,9);
1160        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1161                PageTableEntry::sun4u);
1162        tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1163                pte, entry_insert);
1164        break;
1165      case ASI_DTLB_DATA_ACCESS_REG:
1166        entry_insert = bits(va, 8,3);
1167      case ASI_DTLB_DATA_IN_REG:
1168        assert(entry_insert != -1 || mbits(va,10,9) == va);
1169        ta_insert = tag_access;
1170        va_insert = mbits(ta_insert, 63,13);
1171        ct_insert = mbits(ta_insert, 12,0);
1172        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1173        real_insert = bits(va, 9,9);
1174        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1175                PageTableEntry::sun4u);
1176        insert(va_insert, part_insert, ct_insert, real_insert, pte,
1177               entry_insert);
1178        break;
1179      case ASI_IMMU_DEMAP:
1180        ignore = false;
1181        ctx_id = -1;
1182        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1183        switch (bits(va,5,4)) {
1184          case 0:
1185            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1186            break;
1187          case 1:
1188            ignore = true;
1189            break;
1190          case 3:
1191            ctx_id = 0;
1192            break;
1193          default:
1194            ignore = true;
1195        }
1196
1197        switch(bits(va,7,6)) {
1198          case 0: // demap page
1199            if (!ignore)
1200                tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1201                        bits(va,9,9), ctx_id);
1202            break;
1203          case 1: //demap context
1204            if (!ignore)
1205                tc->getITBPtr()->demapContext(part_id, ctx_id);
1206            break;
1207          case 2:
1208            tc->getITBPtr()->demapAll(part_id);
1209            break;
1210          default:
1211            panic("Invalid type for IMMU demap\n");
1212        }
1213        break;
1214      case ASI_DMMU:
1215        switch (va) {
1216          case 0x18:
1217            sfsr = data;
1218            break;
1219          case 0x30:
1220            sext<59>(bits(data, 59,0));
1221            tag_access = data;
1222            break;
1223          case 0x80:
1224            tc->setMiscReg(MISCREG_MMU_PART_ID, data);
1225            break;
1226          default:
1227            goto doMmuWriteError;
1228        }
1229        break;
1230      case ASI_DMMU_DEMAP:
1231        ignore = false;
1232        ctx_id = -1;
1233        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1234        switch (bits(va,5,4)) {
1235          case 0:
1236            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1237            break;
1238          case 1:
1239            ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
1240            break;
1241          case 3:
1242            ctx_id = 0;
1243            break;
1244          default:
1245            ignore = true;
1246        }
1247
1248        switch(bits(va,7,6)) {
1249          case 0: // demap page
1250            if (!ignore)
1251                demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1252            break;
1253          case 1: //demap context
1254            if (!ignore)
1255                demapContext(part_id, ctx_id);
1256            break;
1257          case 2:
1258            demapAll(part_id);
1259            break;
1260          default:
1261            panic("Invalid type for IMMU demap\n");
1262        }
1263        break;
1264       case ASI_SWVR_INTR_RECEIVE:
1265        {
1266            int msb;
1267            // clear all the interrupts that aren't set in the write
1268            SparcISA::Interrupts * interrupts =
1269                dynamic_cast<SparcISA::Interrupts *>(
1270                        tc->getCpuPtr()->getInterruptController());
1271            while (interrupts->get_vec(IT_INT_VEC) & data) {
1272                msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
1273                tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb);
1274            }
1275        }
1276        break;
1277      case ASI_SWVR_UDB_INTR_W:
1278            tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
1279            postInterrupt(bits(data, 5, 0), 0);
1280        break;
1281      default:
1282doMmuWriteError:
1283        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1284            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1285    }
1286    pkt->makeAtomicResponse();
1287    return tc->getCpuPtr()->ticks(1);
1288}
1289
1290#endif
1291
1292void
1293DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
1294{
1295    uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0);
1296    ITB * itb = tc->getITBPtr();
1297    ptrs[0] = MakeTsbPtr(Ps0, tag_access,
1298                c0_tsb_ps0,
1299                c0_config,
1300                cx_tsb_ps0,
1301                cx_config);
1302    ptrs[1] = MakeTsbPtr(Ps1, tag_access,
1303                c0_tsb_ps1,
1304                c0_config,
1305                cx_tsb_ps1,
1306                cx_config);
1307    ptrs[2] = MakeTsbPtr(Ps0, tag_access,
1308                itb->c0_tsb_ps0,
1309                itb->c0_config,
1310                itb->cx_tsb_ps0,
1311                itb->cx_config);
1312    ptrs[3] = MakeTsbPtr(Ps1, tag_access,
1313                itb->c0_tsb_ps1,
1314                itb->c0_config,
1315                itb->cx_tsb_ps1,
1316                itb->cx_config);
1317}
1318
1319uint64_t
1320DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
1321        uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
1322{
1323    uint64_t tsb;
1324    uint64_t config;
1325
1326    if (bits(tag_access, 12,0) == 0) {
1327        tsb = c0_tsb;
1328        config = c0_config;
1329    } else {
1330        tsb = cX_tsb;
1331        config = cX_config;
1332    }
1333
1334    uint64_t ptr = mbits(tsb,63,13);
1335    bool split = bits(tsb,12,12);
1336    int tsb_size = bits(tsb,3,0);
1337    int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8);
1338
1339    if (ps == Ps1  && split)
1340        ptr |= ULL(1) << (13 + tsb_size);
1341    ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4);
1342
1343    return ptr;
1344}
1345
1346void
1347TLB::serialize(std::ostream &os)
1348{
1349    SERIALIZE_SCALAR(size);
1350    SERIALIZE_SCALAR(usedEntries);
1351    SERIALIZE_SCALAR(lastReplaced);
1352
1353    // convert the pointer based free list into an index based one
1354    int *free_list = (int*)malloc(sizeof(int) * size);
1355    int cntr = 0;
1356    std::list<TlbEntry*>::iterator i;
1357    i = freeList.begin();
1358    while (i != freeList.end()) {
1359        free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry);
1360        i++;
1361    }
1362    SERIALIZE_SCALAR(cntr);
1363    SERIALIZE_ARRAY(free_list,  cntr);
1364
1365    SERIALIZE_SCALAR(c0_tsb_ps0);
1366    SERIALIZE_SCALAR(c0_tsb_ps1);
1367    SERIALIZE_SCALAR(c0_config);
1368    SERIALIZE_SCALAR(cx_tsb_ps0);
1369    SERIALIZE_SCALAR(cx_tsb_ps1);
1370    SERIALIZE_SCALAR(cx_config);
1371    SERIALIZE_SCALAR(sfsr);
1372    SERIALIZE_SCALAR(tag_access);
1373
1374    for (int x = 0; x < size; x++) {
1375        nameOut(os, csprintf("%s.PTE%d", name(), x));
1376        tlb[x].serialize(os);
1377    }
1378}
1379
1380void
1381TLB::unserialize(Checkpoint *cp, const std::string &section)
1382{
1383    int oldSize;
1384
1385    paramIn(cp, section, "size", oldSize);
1386    if (oldSize != size)
1387        panic("Don't support unserializing different sized TLBs\n");
1388    UNSERIALIZE_SCALAR(usedEntries);
1389    UNSERIALIZE_SCALAR(lastReplaced);
1390
1391    int cntr;
1392    UNSERIALIZE_SCALAR(cntr);
1393
1394    int *free_list = (int*)malloc(sizeof(int) * cntr);
1395    freeList.clear();
1396    UNSERIALIZE_ARRAY(free_list,  cntr);
1397    for (int x = 0; x < cntr; x++)
1398        freeList.push_back(&tlb[free_list[x]]);
1399
1400    UNSERIALIZE_SCALAR(c0_tsb_ps0);
1401    UNSERIALIZE_SCALAR(c0_tsb_ps1);
1402    UNSERIALIZE_SCALAR(c0_config);
1403    UNSERIALIZE_SCALAR(cx_tsb_ps0);
1404    UNSERIALIZE_SCALAR(cx_tsb_ps1);
1405    UNSERIALIZE_SCALAR(cx_config);
1406    UNSERIALIZE_SCALAR(sfsr);
1407    UNSERIALIZE_SCALAR(tag_access);
1408
1409    lookupTable.clear();
1410    for (int x = 0; x < size; x++) {
1411        tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
1412        if (tlb[x].valid)
1413            lookupTable.insert(tlb[x].range, &tlb[x]);
1414
1415    }
1416}
1417
1418void
1419DTB::serialize(std::ostream &os)
1420{
1421    TLB::serialize(os);
1422    SERIALIZE_SCALAR(sfar);
1423}
1424
1425void
1426DTB::unserialize(Checkpoint *cp, const std::string &section)
1427{
1428    TLB::unserialize(cp, section);
1429    UNSERIALIZE_SCALAR(sfar);
1430}
1431
1432/* end namespace SparcISA */ }
1433
1434SparcISA::ITB *
1435SparcITBParams::create()
1436{
1437    return new SparcISA::ITB(this);
1438}
1439
1440SparcISA::DTB *
1441SparcDTBParams::create()
1442{
1443    return new SparcISA::DTB(this);
1444}
1445