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