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