tlb.cc revision 3824:8900576818d7
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
332    assert(req->getAsi() == ASI_IMPLICIT);
333
334    if (tl > 0) {
335        asi = ASI_N;
336        ct = Nucleus;
337        context = 0;
338    } else {
339        asi = ASI_P;
340        ct = Primary;
341        context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
342    }
343
344    if ( hpstate >> 2 & 0x1 || hpstate >> 5 & 0x1 ) {
345        req->setPaddr(req->getVaddr() & PAddrImplMask);
346        return NoFault;
347    }
348
349    // If the asi is unaligned trap
350    if (vaddr & 0x7) {
351        writeSfsr(tc, false, ct, false, OtherFault, asi);
352        return new MemAddressNotAligned;
353    }
354
355    if (addr_mask)
356        vaddr = vaddr & VAddrAMask;
357
358    if (!validVirtualAddress(vaddr, addr_mask)) {
359        writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
360        return new InstructionAccessException;
361    }
362
363    if (lsuIm) {
364        e = lookup(req->getVaddr(), part_id, true);
365        real = true;
366        context = 0;
367    } else {
368        e = lookup(vaddr, part_id, false, context);
369    }
370
371    if (e == NULL || !e->valid) {
372        tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
373                vaddr & ~BytesInPageMask | context);
374        if (real)
375            return new InstructionRealTranslationMiss;
376        else
377            return new FastInstructionAccessMMUMiss;
378    }
379
380    // were not priviledged accesing priv page
381    if (!priv && e->pte.priv()) {
382        writeSfsr(tc, false, ct, false, PrivViolation, asi);
383        return new InstructionAccessException;
384    }
385
386    req->setPaddr(e->pte.paddr() & ~e->pte.size() |
387                  req->getVaddr() & e->pte.size());
388    return NoFault;
389}
390
391
392
393Fault
394DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
395{
396    /* @todo this could really use some profiling and fixing to make it faster! */
397    uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE);
398    uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE);
399    bool lsuDm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 3 & 0x1;
400    uint64_t tl = tc->readMiscReg(MISCREG_TL);
401    uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
402    bool hpriv = hpstate >> 2 & 0x1;
403    bool red = hpstate >> 5 >> 0x1;
404    bool addr_mask = pstate >> 3 & 0x1;
405    bool priv = pstate >> 2 & 0x1;
406    bool implicit = false;
407    bool real = false;
408    Addr vaddr = req->getVaddr();
409    Addr size = req->getSize();
410    ContextType ct;
411    int context;
412    ASI asi;
413
414    TlbEntry *e;
415
416    asi = (ASI)req->getAsi();
417    DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
418            vaddr, size, asi);
419
420    if (asi == ASI_IMPLICIT)
421        implicit = true;
422
423    if (implicit) {
424        if (tl > 0) {
425            asi = ASI_N;
426            ct = Nucleus;
427            context = 0;
428        } else {
429            asi = ASI_P;
430            ct = Primary;
431            context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
432        }
433    } else if (!hpriv && !red) {
434        if (tl > 0 || AsiIsNucleus(asi)) {
435            ct = Nucleus;
436            context = 0;
437        } else if (AsiIsSecondary(asi)) {
438            ct = Secondary;
439            context = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
440        } else {
441            context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
442            ct = Primary; //???
443        }
444
445        // We need to check for priv level/asi priv
446        if (!priv && !AsiIsUnPriv(asi)) {
447            // It appears that context should be Nucleus in these cases?
448            writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
449            return new PrivilegedAction;
450        }
451        if (priv && AsiIsHPriv(asi)) {
452            writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
453            return new DataAccessException;
454        }
455
456    }
457
458    // If the asi is unaligned trap
459    if (vaddr & size-1) {
460        writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
461        return new MemAddressNotAligned;
462    }
463
464    if (addr_mask)
465        vaddr = vaddr & VAddrAMask;
466
467    if (!validVirtualAddress(vaddr, addr_mask)) {
468        writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
469        return new DataAccessException;
470    }
471
472    if (!implicit) {
473        if (AsiIsLittle(asi))
474            panic("Little Endian ASIs not supported\n");
475        if (AsiIsBlock(asi))
476            panic("Block ASIs not supported\n");
477        if (AsiIsNoFault(asi))
478            panic("No Fault ASIs not supported\n");
479        if (AsiIsTwin(asi))
480            panic("Twin ASIs not supported\n");
481        if (AsiIsPartialStore(asi))
482            panic("Partial Store ASIs not supported\n");
483        if (AsiIsInterrupt(asi))
484            panic("Interrupt ASIs not supported\n");
485
486        if (AsiIsMmu(asi))
487            goto handleMmuRegAccess;
488        if (AsiIsScratchPad(asi))
489            goto handleScratchRegAccess;
490        if (AsiIsQueue(asi))
491            goto handleQueueRegAccess;
492
493        if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
494            panic("Accessing ASI %#X. Should we?\n", asi);
495    }
496
497    if ((!lsuDm && !hpriv) || AsiIsReal(asi)) {
498        real = true;
499        context = 0;
500    };
501
502    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
503        req->setPaddr(req->getVaddr() & PAddrImplMask);
504        return NoFault;
505    }
506
507    e = lookup(req->getVaddr(), part_id, real, context);
508
509    if (e == NULL || !e->valid) {
510        tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
511                vaddr & ~BytesInPageMask | context);
512        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
513        if (real)
514            return new DataRealTranslationMiss;
515        else
516            return new FastDataAccessMMUMiss;
517
518    }
519
520
521    if (write && !e->pte.writable()) {
522        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
523        return new FastDataAccessProtection;
524    }
525
526    if (e->pte.nofault() && !AsiIsNoFault(asi)) {
527        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
528        return new DataAccessException;
529    }
530
531    if (e->pte.sideffect())
532        req->setFlags(req->getFlags() | UNCACHEABLE);
533
534
535    if (!priv && e->pte.priv()) {
536        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
537        return new DataAccessException;
538    }
539
540    req->setPaddr(e->pte.paddr() & ~e->pte.size() |
541                  req->getVaddr() & e->pte.size());
542    return NoFault;
543    /** Normal flow ends here. */
544
545handleScratchRegAccess:
546    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
547        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
548        return new DataAccessException;
549    }
550    goto regAccessOk;
551
552handleQueueRegAccess:
553    if (!priv  && !hpriv) {
554        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
555        return new PrivilegedAction;
556    }
557    if (priv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
558        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
559        return new DataAccessException;
560    }
561    goto regAccessOk;
562
563regAccessOk:
564handleMmuRegAccess:
565    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
566    req->setMmapedIpr(true);
567    req->setPaddr(req->getVaddr());
568    return NoFault;
569};
570
571Tick
572DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
573{
574    Addr va = pkt->getAddr();
575    ASI asi = (ASI)pkt->req->getAsi();
576
577    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
578         (uint32_t)pkt->req->getAsi(), pkt->getAddr());
579
580    switch (asi) {
581      case ASI_LSU_CONTROL_REG:
582        assert(va == 0);
583        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
584        break;
585      case ASI_MMU:
586        switch (va) {
587          case 0x8:
588            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
589            break;
590          case 0x10:
591            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
592            break;
593          default:
594            goto doMmuReadError;
595        }
596        break;
597      case ASI_QUEUE:
598        pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
599                    (va >> 4) - 0x3c));
600        break;
601      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
602        assert(va == 0);
603        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
604        break;
605      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
606        assert(va == 0);
607        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
608        break;
609      case ASI_DMMU_CTXT_ZERO_CONFIG:
610        assert(va == 0);
611        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
612        break;
613      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
614        assert(va == 0);
615        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
616        break;
617      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
618        assert(va == 0);
619        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
620        break;
621      case ASI_IMMU_CTXT_ZERO_CONFIG:
622        assert(va == 0);
623        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
624        break;
625      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
626        assert(va == 0);
627        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
628        break;
629      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
630        assert(va == 0);
631        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
632        break;
633      case ASI_DMMU_CTXT_NONZERO_CONFIG:
634        assert(va == 0);
635        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
636        break;
637      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
638        assert(va == 0);
639        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
640        break;
641      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
642        assert(va == 0);
643        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
644        break;
645      case ASI_IMMU_CTXT_NONZERO_CONFIG:
646        assert(va == 0);
647        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
648        break;
649      case ASI_HYP_SCRATCHPAD:
650      case ASI_SCRATCHPAD:
651        pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
652        break;
653      case ASI_DMMU:
654        switch (va) {
655          case 0x80:
656            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
657            break;
658          default:
659                goto doMmuReadError;
660        }
661        break;
662      default:
663doMmuReadError:
664        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
665            (uint32_t)asi, va);
666    }
667    pkt->result = Packet::Success;
668    return tc->getCpuPtr()->cycles(1);
669}
670
671Tick
672DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
673{
674    uint64_t data = gtoh(pkt->get<uint64_t>());
675    Addr va = pkt->getAddr();
676    ASI asi = (ASI)pkt->req->getAsi();
677
678    DPRINTF(IPR, "Memory Mapped IPR Write: asi=#%X a=%#x d=%#X\n",
679         (uint32_t)asi, va, data);
680
681    switch (asi) {
682      case ASI_LSU_CONTROL_REG:
683        assert(va == 0);
684        tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
685        break;
686      case ASI_MMU:
687        switch (va) {
688          case 0x8:
689            tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
690            break;
691          case 0x10:
692            tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
693            break;
694          default:
695            goto doMmuWriteError;
696        }
697        break;
698      case ASI_QUEUE:
699        assert(mbits(va,13,6) == va);
700        tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
701                    (va >> 4) - 0x3c, data);
702        break;
703      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
704        assert(va == 0);
705        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
706        break;
707      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
708        assert(va == 0);
709        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
710        break;
711      case ASI_DMMU_CTXT_ZERO_CONFIG:
712        assert(va == 0);
713        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
714        break;
715      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
716        assert(va == 0);
717        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
718        break;
719      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
720        assert(va == 0);
721        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
722        break;
723      case ASI_IMMU_CTXT_ZERO_CONFIG:
724        assert(va == 0);
725        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
726        break;
727      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
728        assert(va == 0);
729        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
730        break;
731      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
732        assert(va == 0);
733        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
734        break;
735      case ASI_DMMU_CTXT_NONZERO_CONFIG:
736        assert(va == 0);
737        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
738        break;
739      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
740        assert(va == 0);
741        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
742        break;
743      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
744        assert(va == 0);
745        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
746        break;
747      case ASI_IMMU_CTXT_NONZERO_CONFIG:
748        assert(va == 0);
749        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
750        break;
751      case ASI_HYP_SCRATCHPAD:
752      case ASI_SCRATCHPAD:
753        tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
754        break;
755      case ASI_DMMU:
756        switch (va) {
757          case 0x80:
758            tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
759            break;
760          default:
761            goto doMmuWriteError;
762        }
763        break;
764      default:
765doMmuWriteError:
766        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
767            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
768    }
769    pkt->result = Packet::Success;
770    return tc->getCpuPtr()->cycles(1);
771}
772
773void
774TLB::serialize(std::ostream &os)
775{
776    panic("Need to implement serialize tlb for SPARC\n");
777}
778
779void
780TLB::unserialize(Checkpoint *cp, const std::string &section)
781{
782    panic("Need to implement unserialize tlb for SPARC\n");
783}
784
785
786DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
787
788BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
789
790    Param<int> size;
791
792END_DECLARE_SIM_OBJECT_PARAMS(ITB)
793
794BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
795
796    INIT_PARAM_DFLT(size, "TLB size", 48)
797
798END_INIT_SIM_OBJECT_PARAMS(ITB)
799
800
801CREATE_SIM_OBJECT(ITB)
802{
803    return new ITB(getInstanceName(), size);
804}
805
806REGISTER_SIM_OBJECT("SparcITB", ITB)
807
808BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
809
810    Param<int> size;
811
812END_DECLARE_SIM_OBJECT_PARAMS(DTB)
813
814BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
815
816    INIT_PARAM_DFLT(size, "TLB size", 64)
817
818END_INIT_SIM_OBJECT_PARAMS(DTB)
819
820
821CREATE_SIM_OBJECT(DTB)
822{
823    return new DTB(getInstanceName(), size);
824}
825
826REGISTER_SIM_OBJECT("SparcDTB", DTB)
827}
828