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