tlb.cc revision 3881
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    } else if (hpriv) {
629        if (asi == ASI_P) {
630            ct = Primary;
631            context = pri_context;
632            goto continueDtbFlow;
633        }
634    }
635
636    if (!implicit) {
637        if (AsiIsLittle(asi))
638            panic("Little Endian ASIs not supported\n");
639        if (AsiIsBlock(asi))
640            panic("Block ASIs not supported\n");
641        if (AsiIsNoFault(asi))
642            panic("No Fault ASIs not supported\n");
643        if (write && asi == ASI_LDTX_P)
644            // block init store (like write hint64)
645            goto continueDtbFlow;
646        if (!write && asi == ASI_QUAD_LDD)
647            goto continueDtbFlow;
648
649        if (AsiIsTwin(asi))
650            panic("Twin ASIs not supported\n");
651        if (AsiIsPartialStore(asi))
652            panic("Partial Store ASIs not supported\n");
653        if (AsiIsInterrupt(asi))
654            panic("Interrupt ASIs not supported\n");
655
656        if (AsiIsMmu(asi))
657            goto handleMmuRegAccess;
658        if (AsiIsScratchPad(asi))
659            goto handleScratchRegAccess;
660        if (AsiIsQueue(asi))
661            goto handleQueueRegAccess;
662        if (AsiIsSparcError(asi))
663            goto handleSparcErrorRegAccess;
664
665        if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
666            panic("Accessing ASI %#X. Should we?\n", asi);
667    }
668
669continueDtbFlow:
670    // If the asi is unaligned trap
671    if (vaddr & size-1) {
672        writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
673        return new MemAddressNotAligned;
674    }
675
676    if (addr_mask)
677        vaddr = vaddr & VAddrAMask;
678
679    if (!validVirtualAddress(vaddr, addr_mask)) {
680        writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
681        return new DataAccessException;
682    }
683
684
685    if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
686        real = true;
687        context = 0;
688    };
689
690    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
691        req->setPaddr(vaddr & PAddrImplMask);
692        return NoFault;
693    }
694
695    e = lookup(vaddr, part_id, real, context);
696
697    if (e == NULL || !e->valid) {
698        tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
699                vaddr & ~BytesInPageMask | context);
700        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
701        if (real)
702            return new DataRealTranslationMiss;
703        else
704            return new FastDataAccessMMUMiss;
705
706    }
707
708
709    if (write && !e->pte.writable()) {
710        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
711        return new FastDataAccessProtection;
712    }
713
714    if (e->pte.nofault() && !AsiIsNoFault(asi)) {
715        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
716        return new DataAccessException;
717    }
718
719    if (e->pte.sideffect())
720        req->setFlags(req->getFlags() | UNCACHEABLE);
721
722
723    if (!priv && e->pte.priv()) {
724        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
725        return new DataAccessException;
726    }
727
728    // cache translation date for next translation
729    cacheState = tlbdata;
730    if (!cacheValid) {
731        cacheEntry[1] = NULL;
732        cacheEntry[0] = NULL;
733    }
734
735    if (cacheEntry[0] != e && cacheEntry[1] != e) {
736        cacheEntry[1] = cacheEntry[0];
737        cacheEntry[0] = e;
738        cacheAsi[1] = cacheAsi[0];
739        cacheAsi[0] = asi;
740        if (implicit)
741            cacheAsi[0] = (ASI)0;
742    }
743    cacheValid = true;
744    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
745                  vaddr & e->pte.size()-1);
746    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
747    return NoFault;
748    /** Normal flow ends here. */
749
750handleScratchRegAccess:
751    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
752        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
753        return new DataAccessException;
754    }
755    goto regAccessOk;
756
757handleQueueRegAccess:
758    if (!priv  && !hpriv) {
759        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
760        return new PrivilegedAction;
761    }
762    if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
763        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
764        return new DataAccessException;
765    }
766    goto regAccessOk;
767
768handleSparcErrorRegAccess:
769    if (!hpriv) {
770        if (priv) {
771            writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
772            return new DataAccessException;
773        } else {
774            writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
775            return new PrivilegedAction;
776        }
777    }
778    goto regAccessOk;
779
780
781regAccessOk:
782handleMmuRegAccess:
783    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
784    req->setMmapedIpr(true);
785    req->setPaddr(req->getVaddr());
786    return NoFault;
787};
788
789Tick
790DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
791{
792    Addr va = pkt->getAddr();
793    ASI asi = (ASI)pkt->req->getAsi();
794    uint64_t temp, data;
795    uint64_t tsbtemp, cnftemp;
796
797    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
798         (uint32_t)pkt->req->getAsi(), pkt->getAddr());
799
800    switch (asi) {
801      case ASI_LSU_CONTROL_REG:
802        assert(va == 0);
803        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
804        break;
805      case ASI_MMU:
806        switch (va) {
807          case 0x8:
808            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
809            break;
810          case 0x10:
811            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
812            break;
813          default:
814            goto doMmuReadError;
815        }
816        break;
817      case ASI_QUEUE:
818        pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
819                    (va >> 4) - 0x3c));
820        break;
821      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
822        assert(va == 0);
823        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
824        break;
825      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
826        assert(va == 0);
827        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
828        break;
829      case ASI_DMMU_CTXT_ZERO_CONFIG:
830        assert(va == 0);
831        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
832        break;
833      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
834        assert(va == 0);
835        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
836        break;
837      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
838        assert(va == 0);
839        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
840        break;
841      case ASI_IMMU_CTXT_ZERO_CONFIG:
842        assert(va == 0);
843        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
844        break;
845      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
846        assert(va == 0);
847        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
848        break;
849      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
850        assert(va == 0);
851        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
852        break;
853      case ASI_DMMU_CTXT_NONZERO_CONFIG:
854        assert(va == 0);
855        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
856        break;
857      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
858        assert(va == 0);
859        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
860        break;
861      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
862        assert(va == 0);
863        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
864        break;
865      case ASI_IMMU_CTXT_NONZERO_CONFIG:
866        assert(va == 0);
867        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
868        break;
869      case ASI_SPARC_ERROR_STATUS_REG:
870        warn("returning 0 for  SPARC ERROR regsiter read\n");
871        pkt->set(0);
872        break;
873      case ASI_HYP_SCRATCHPAD:
874      case ASI_SCRATCHPAD:
875        pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
876        break;
877      case ASI_IMMU:
878        switch (va) {
879          case 0x0:
880            temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
881            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
882            break;
883          case 0x30:
884            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
885            break;
886          default:
887            goto doMmuReadError;
888        }
889        break;
890      case ASI_DMMU:
891        switch (va) {
892          case 0x0:
893            temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
894            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
895            break;
896          case 0x30:
897            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
898            break;
899          case 0x80:
900            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
901            break;
902          default:
903                goto doMmuReadError;
904        }
905        break;
906      case ASI_DMMU_TSB_PS0_PTR_REG:
907        temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
908        if (bits(temp,12,0) == 0) {
909            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
910            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
911        } else {
912            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
913            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
914        }
915        data = mbits(tsbtemp,63,13);
916        data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
917            mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
918        pkt->set(data);
919        break;
920      case ASI_DMMU_TSB_PS1_PTR_REG:
921        temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
922        if (bits(temp,12,0) == 0) {
923            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
924            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
925        } else {
926            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
927            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
928        }
929        data = mbits(tsbtemp,63,13);
930        if (bits(tsbtemp,12,12))
931            data |= ULL(1) << (13+bits(tsbtemp,3,0));
932        data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
933            mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
934        pkt->set(data);
935        break;
936
937      default:
938doMmuReadError:
939        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
940            (uint32_t)asi, va);
941    }
942    pkt->result = Packet::Success;
943    return tc->getCpuPtr()->cycles(1);
944}
945
946Tick
947DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
948{
949    uint64_t data = gtoh(pkt->get<uint64_t>());
950    Addr va = pkt->getAddr();
951    ASI asi = (ASI)pkt->req->getAsi();
952
953    Addr ta_insert;
954    Addr va_insert;
955    Addr ct_insert;
956    int part_insert;
957    int entry_insert = -1;
958    bool real_insert;
959    bool ignore;
960    int part_id;
961    int ctx_id;
962    PageTableEntry pte;
963
964    DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
965         (uint32_t)asi, va, data);
966
967    switch (asi) {
968      case ASI_LSU_CONTROL_REG:
969        assert(va == 0);
970        tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
971        break;
972      case ASI_MMU:
973        switch (va) {
974          case 0x8:
975            tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
976            break;
977          case 0x10:
978            tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
979            break;
980          default:
981            goto doMmuWriteError;
982        }
983        break;
984      case ASI_QUEUE:
985        assert(mbits(data,13,6) == data);
986        tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
987                    (va >> 4) - 0x3c, data);
988        break;
989      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
990        assert(va == 0);
991        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
992        break;
993      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
994        assert(va == 0);
995        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
996        break;
997      case ASI_DMMU_CTXT_ZERO_CONFIG:
998        assert(va == 0);
999        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
1000        break;
1001      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1002        assert(va == 0);
1003        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
1004        break;
1005      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1006        assert(va == 0);
1007        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
1008        break;
1009      case ASI_IMMU_CTXT_ZERO_CONFIG:
1010        assert(va == 0);
1011        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
1012        break;
1013      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1014        assert(va == 0);
1015        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
1016        break;
1017      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1018        assert(va == 0);
1019        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
1020        break;
1021      case ASI_DMMU_CTXT_NONZERO_CONFIG:
1022        assert(va == 0);
1023        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
1024        break;
1025      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1026        assert(va == 0);
1027        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
1028        break;
1029      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1030        assert(va == 0);
1031        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
1032        break;
1033      case ASI_IMMU_CTXT_NONZERO_CONFIG:
1034        assert(va == 0);
1035        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
1036        break;
1037      case ASI_SPARC_ERROR_EN_REG:
1038      case ASI_SPARC_ERROR_STATUS_REG:
1039        warn("Ignoring write to SPARC ERROR regsiter\n");
1040        break;
1041      case ASI_HYP_SCRATCHPAD:
1042      case ASI_SCRATCHPAD:
1043        tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1044        break;
1045      case ASI_IMMU:
1046        switch (va) {
1047          case 0x30:
1048            tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
1049            break;
1050          default:
1051            goto doMmuWriteError;
1052        }
1053        break;
1054      case ASI_ITLB_DATA_ACCESS_REG:
1055        entry_insert = bits(va, 8,3);
1056      case ASI_ITLB_DATA_IN_REG:
1057        assert(entry_insert != -1 || mbits(va,10,9) == va);
1058        ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
1059        va_insert = mbits(ta_insert, 63,13);
1060        ct_insert = mbits(ta_insert, 12,0);
1061        part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1062        real_insert = bits(va, 9,9);
1063        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1064                PageTableEntry::sun4u);
1065        tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1066                pte, entry_insert);
1067        break;
1068      case ASI_DTLB_DATA_ACCESS_REG:
1069        entry_insert = bits(va, 8,3);
1070      case ASI_DTLB_DATA_IN_REG:
1071        assert(entry_insert != -1 || mbits(va,10,9) == va);
1072        ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
1073        va_insert = mbits(ta_insert, 63,13);
1074        ct_insert = mbits(ta_insert, 12,0);
1075        part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1076        real_insert = bits(va, 9,9);
1077        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1078                PageTableEntry::sun4u);
1079        insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1080        break;
1081      case ASI_IMMU_DEMAP:
1082        ignore = false;
1083        ctx_id = -1;
1084        part_id =  tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1085        switch (bits(va,5,4)) {
1086          case 0:
1087            ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1088            break;
1089          case 1:
1090            ignore = true;
1091            break;
1092          case 3:
1093            ctx_id = 0;
1094            break;
1095          default:
1096            ignore = true;
1097        }
1098
1099        switch(bits(va,7,6)) {
1100          case 0: // demap page
1101            if (!ignore)
1102                tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1103                        bits(va,9,9), ctx_id);
1104            break;
1105          case 1: //demap context
1106            if (!ignore)
1107                tc->getITBPtr()->demapContext(part_id, ctx_id);
1108            break;
1109          case 2:
1110            tc->getITBPtr()->demapAll(part_id);
1111            break;
1112          default:
1113            panic("Invalid type for IMMU demap\n");
1114        }
1115        break;
1116      case ASI_DMMU:
1117        switch (va) {
1118          case 0x30:
1119            tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1120            break;
1121          case 0x80:
1122            tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1123            break;
1124          default:
1125            goto doMmuWriteError;
1126        }
1127        break;
1128      case ASI_DMMU_DEMAP:
1129        ignore = false;
1130        ctx_id = -1;
1131        part_id =  tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1132        switch (bits(va,5,4)) {
1133          case 0:
1134            ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1135            break;
1136          case 1:
1137            ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT);
1138            break;
1139          case 3:
1140            ctx_id = 0;
1141            break;
1142          default:
1143            ignore = true;
1144        }
1145
1146        switch(bits(va,7,6)) {
1147          case 0: // demap page
1148            if (!ignore)
1149                demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1150            break;
1151          case 1: //demap context
1152            if (!ignore)
1153                demapContext(part_id, ctx_id);
1154            break;
1155          case 2:
1156            demapAll(part_id);
1157            break;
1158          default:
1159            panic("Invalid type for IMMU demap\n");
1160        }
1161        break;
1162      default:
1163doMmuWriteError:
1164        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1165            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1166    }
1167    pkt->result = Packet::Success;
1168    return tc->getCpuPtr()->cycles(1);
1169}
1170
1171void
1172TLB::serialize(std::ostream &os)
1173{
1174    panic("Need to implement serialize tlb for SPARC\n");
1175}
1176
1177void
1178TLB::unserialize(Checkpoint *cp, const std::string &section)
1179{
1180    panic("Need to implement unserialize tlb for SPARC\n");
1181}
1182
1183
1184DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1185
1186BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1187
1188    Param<int> size;
1189
1190END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1191
1192BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1193
1194    INIT_PARAM_DFLT(size, "TLB size", 48)
1195
1196END_INIT_SIM_OBJECT_PARAMS(ITB)
1197
1198
1199CREATE_SIM_OBJECT(ITB)
1200{
1201    return new ITB(getInstanceName(), size);
1202}
1203
1204REGISTER_SIM_OBJECT("SparcITB", ITB)
1205
1206BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1207
1208    Param<int> size;
1209
1210END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1211
1212BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1213
1214    INIT_PARAM_DFLT(size, "TLB size", 64)
1215
1216END_INIT_SIM_OBJECT_PARAMS(DTB)
1217
1218
1219CREATE_SIM_OBJECT(DTB)
1220{
1221    return new DTB(getInstanceName(), size);
1222}
1223
1224REGISTER_SIM_OBJECT("SparcDTB", DTB)
1225}
1226