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