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