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