tlb.cc revision 3856
19897Sandreas@sandberg.pp.se/*
29897Sandreas@sandberg.pp.se * Copyright (c) 2001-2005 The Regents of The University of Michigan
39897Sandreas@sandberg.pp.se * All rights reserved.
49897Sandreas@sandberg.pp.se *
59897Sandreas@sandberg.pp.se * Redistribution and use in source and binary forms, with or without
69897Sandreas@sandberg.pp.se * modification, are permitted provided that the following conditions are
79897Sandreas@sandberg.pp.se * met: redistributions of source code must retain the above copyright
89897Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer;
99897Sandreas@sandberg.pp.se * redistributions in binary form must reproduce the above copyright
109897Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer in the
119897Sandreas@sandberg.pp.se * documentation and/or other materials provided with the distribution;
129897Sandreas@sandberg.pp.se * neither the name of the copyright holders nor the names of its
139897Sandreas@sandberg.pp.se * contributors may be used to endorse or promote products derived from
149897Sandreas@sandberg.pp.se * this software without specific prior written permission.
159897Sandreas@sandberg.pp.se *
169897Sandreas@sandberg.pp.se * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179897Sandreas@sandberg.pp.se * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189897Sandreas@sandberg.pp.se * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199897Sandreas@sandberg.pp.se * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209897Sandreas@sandberg.pp.se * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219897Sandreas@sandberg.pp.se * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229897Sandreas@sandberg.pp.se * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239897Sandreas@sandberg.pp.se * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249897Sandreas@sandberg.pp.se * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259897Sandreas@sandberg.pp.se * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269897Sandreas@sandberg.pp.se * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279897Sandreas@sandberg.pp.se *
289897Sandreas@sandberg.pp.se * Authors: Ali Saidi
299897Sandreas@sandberg.pp.se */
309897Sandreas@sandberg.pp.se
319897Sandreas@sandberg.pp.se#include "arch/sparc/asi.hh"
329897Sandreas@sandberg.pp.se#include "arch/sparc/miscregfile.hh"
339897Sandreas@sandberg.pp.se#include "arch/sparc/tlb.hh"
349897Sandreas@sandberg.pp.se#include "base/bitfield.hh"
359897Sandreas@sandberg.pp.se#include "base/trace.hh"
369897Sandreas@sandberg.pp.se#include "cpu/thread_context.hh"
379897Sandreas@sandberg.pp.se#include "cpu/base.hh"
389897Sandreas@sandberg.pp.se#include "mem/packet_access.hh"
399897Sandreas@sandberg.pp.se#include "mem/request.hh"
409897Sandreas@sandberg.pp.se#include "sim/builder.hh"
419897Sandreas@sandberg.pp.se
429897Sandreas@sandberg.pp.se/* @todo remove some of the magic constants.  -- ali
439897Sandreas@sandberg.pp.se * */
449897Sandreas@sandberg.pp.senamespace SparcISA
459897Sandreas@sandberg.pp.se{
469897Sandreas@sandberg.pp.se
479897Sandreas@sandberg.pp.seTLB::TLB(const std::string &name, int s)
489897Sandreas@sandberg.pp.se    : SimObject(name), size(s), usedEntries(0), cacheValid(false)
499897Sandreas@sandberg.pp.se{
509897Sandreas@sandberg.pp.se    // To make this work you'll have to change the hypervisor and OS
519897Sandreas@sandberg.pp.se    if (size > 64)
529897Sandreas@sandberg.pp.se        fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
539897Sandreas@sandberg.pp.se
549897Sandreas@sandberg.pp.se    tlb = new TlbEntry[size];
559897Sandreas@sandberg.pp.se    memset(tlb, 0, sizeof(TlbEntry) * size);
569897Sandreas@sandberg.pp.se}
579897Sandreas@sandberg.pp.se
589897Sandreas@sandberg.pp.sevoid
599897Sandreas@sandberg.pp.seTLB::clearUsedBits()
609897Sandreas@sandberg.pp.se{
619897Sandreas@sandberg.pp.se    MapIter i;
629897Sandreas@sandberg.pp.se    for (i = lookupTable.begin(); i != lookupTable.end();) {
639897Sandreas@sandberg.pp.se        TlbEntry *t = i->second;
649897Sandreas@sandberg.pp.se        if (!t->pte.locked()) {
659897Sandreas@sandberg.pp.se            t->used = false;
669897Sandreas@sandberg.pp.se            usedEntries--;
679897Sandreas@sandberg.pp.se        }
689897Sandreas@sandberg.pp.se    }
699897Sandreas@sandberg.pp.se}
709897Sandreas@sandberg.pp.se
719897Sandreas@sandberg.pp.se
729897Sandreas@sandberg.pp.sevoid
739897Sandreas@sandberg.pp.seTLB::insert(Addr va, int partition_id, int context_id, bool real,
749897Sandreas@sandberg.pp.se        const PageTableEntry& PTE, int entry)
759897Sandreas@sandberg.pp.se{
769897Sandreas@sandberg.pp.se
779897Sandreas@sandberg.pp.se
789897Sandreas@sandberg.pp.se    MapIter i;
799897Sandreas@sandberg.pp.se    TlbEntry *new_entry = NULL;
809897Sandreas@sandberg.pp.se    int x;
819897Sandreas@sandberg.pp.se
829897Sandreas@sandberg.pp.se    cacheValid = false;
839897Sandreas@sandberg.pp.se
849897Sandreas@sandberg.pp.se    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 (!write && asi == ASI_QUAD_LDD)
579            goto continueDtbFlow;
580
581        if (AsiIsTwin(asi))
582            panic("Twin ASIs not supported\n");
583        if (AsiIsPartialStore(asi))
584            panic("Partial Store ASIs not supported\n");
585        if (AsiIsInterrupt(asi))
586            panic("Interrupt ASIs not supported\n");
587
588        if (AsiIsMmu(asi))
589            goto handleMmuRegAccess;
590        if (AsiIsScratchPad(asi))
591            goto handleScratchRegAccess;
592        if (AsiIsQueue(asi))
593            goto handleQueueRegAccess;
594        if (AsiIsSparcError(asi))
595            goto handleSparcErrorRegAccess;
596
597        if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
598            panic("Accessing ASI %#X. Should we?\n", asi);
599    }
600
601continueDtbFlow:
602    // If the asi is unaligned trap
603    if (vaddr & size-1) {
604        writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
605        return new MemAddressNotAligned;
606    }
607
608    if (addr_mask)
609        vaddr = vaddr & VAddrAMask;
610
611    if (!validVirtualAddress(vaddr, addr_mask)) {
612        writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
613        return new DataAccessException;
614    }
615
616
617    if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
618        real = true;
619        context = 0;
620    };
621
622    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
623        req->setPaddr(vaddr & PAddrImplMask);
624        return NoFault;
625    }
626
627    e = lookup(vaddr, part_id, real, context);
628
629    if (e == NULL || !e->valid) {
630        tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
631                vaddr & ~BytesInPageMask | context);
632        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
633        if (real)
634            return new DataRealTranslationMiss;
635        else
636            return new FastDataAccessMMUMiss;
637
638    }
639
640
641    if (write && !e->pte.writable()) {
642        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
643        return new FastDataAccessProtection;
644    }
645
646    if (e->pte.nofault() && !AsiIsNoFault(asi)) {
647        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
648        return new DataAccessException;
649    }
650
651    if (e->pte.sideffect())
652        req->setFlags(req->getFlags() | UNCACHEABLE);
653
654
655    if (!priv && e->pte.priv()) {
656        writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
657        return new DataAccessException;
658    }
659
660    // cache translation date for next translation
661    cacheValid = true;
662    cacheState = tlbdata;
663    if (cacheEntry[0] != e && cacheEntry[1] != e) {
664        cacheEntry[1] = cacheEntry[0];
665        cacheEntry[0] = e;
666        cacheAsi[1] = cacheAsi[0];
667        cacheAsi[0] = asi;
668        if (implicit)
669            cacheAsi[0] = (ASI)0;
670    }
671
672    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
673                  vaddr & e->pte.size()-1);
674    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
675    return NoFault;
676    /** Normal flow ends here. */
677
678handleScratchRegAccess:
679    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
680        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
681        return new DataAccessException;
682    }
683    goto regAccessOk;
684
685handleQueueRegAccess:
686    if (!priv  && !hpriv) {
687        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
688        return new PrivilegedAction;
689    }
690    if (priv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
691        writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
692        return new DataAccessException;
693    }
694    goto regAccessOk;
695
696handleSparcErrorRegAccess:
697    if (!hpriv) {
698        if (priv) {
699            writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
700            return new DataAccessException;
701        } else {
702            writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
703            return new PrivilegedAction;
704        }
705    }
706    goto regAccessOk;
707
708
709regAccessOk:
710handleMmuRegAccess:
711    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
712    req->setMmapedIpr(true);
713    req->setPaddr(req->getVaddr());
714    return NoFault;
715};
716
717Tick
718DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
719{
720    Addr va = pkt->getAddr();
721    ASI asi = (ASI)pkt->req->getAsi();
722    uint64_t temp, data;
723    uint64_t tsbtemp, cnftemp;
724
725    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
726         (uint32_t)pkt->req->getAsi(), pkt->getAddr());
727
728    switch (asi) {
729      case ASI_LSU_CONTROL_REG:
730        assert(va == 0);
731        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
732        break;
733      case ASI_MMU:
734        switch (va) {
735          case 0x8:
736            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
737            break;
738          case 0x10:
739            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
740            break;
741          default:
742            goto doMmuReadError;
743        }
744        break;
745      case ASI_QUEUE:
746        pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
747                    (va >> 4) - 0x3c));
748        break;
749      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
750        assert(va == 0);
751        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
752        break;
753      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
754        assert(va == 0);
755        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
756        break;
757      case ASI_DMMU_CTXT_ZERO_CONFIG:
758        assert(va == 0);
759        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
760        break;
761      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
762        assert(va == 0);
763        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
764        break;
765      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
766        assert(va == 0);
767        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
768        break;
769      case ASI_IMMU_CTXT_ZERO_CONFIG:
770        assert(va == 0);
771        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
772        break;
773      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
774        assert(va == 0);
775        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
776        break;
777      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
778        assert(va == 0);
779        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
780        break;
781      case ASI_DMMU_CTXT_NONZERO_CONFIG:
782        assert(va == 0);
783        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
784        break;
785      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
786        assert(va == 0);
787        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
788        break;
789      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
790        assert(va == 0);
791        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
792        break;
793      case ASI_IMMU_CTXT_NONZERO_CONFIG:
794        assert(va == 0);
795        pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
796        break;
797      case ASI_SPARC_ERROR_STATUS_REG:
798        warn("returning 0 for  SPARC ERROR regsiter read\n");
799        pkt->set(0);
800        break;
801      case ASI_HYP_SCRATCHPAD:
802      case ASI_SCRATCHPAD:
803        pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
804        break;
805      case ASI_IMMU:
806        switch (va) {
807          case 0x0:
808            temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
809            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
810            break;
811          case 0x30:
812            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
813            break;
814          default:
815            goto doMmuReadError;
816        }
817        break;
818      case ASI_DMMU:
819        switch (va) {
820          case 0x0:
821            temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
822            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
823            break;
824          case 0x30:
825            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
826            break;
827          case 0x80:
828            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
829            break;
830          default:
831                goto doMmuReadError;
832        }
833        break;
834      case ASI_DMMU_TSB_PS0_PTR_REG:
835        temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
836        if (bits(temp,12,0) == 0) {
837            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
838            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
839        } else {
840            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
841            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
842        }
843        data = mbits(tsbtemp,63,13);
844        data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
845            mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
846        pkt->set(data);
847        break;
848      case ASI_DMMU_TSB_PS1_PTR_REG:
849        temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
850        if (bits(temp,12,0) == 0) {
851            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
852            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
853        } else {
854            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
855            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
856        }
857        data = mbits(tsbtemp,63,13);
858        if (bits(tsbtemp,12,12))
859            data |= ULL(1) << (13+bits(tsbtemp,3,0));
860        data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
861            mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
862        pkt->set(data);
863        break;
864
865      default:
866doMmuReadError:
867        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
868            (uint32_t)asi, va);
869    }
870    pkt->result = Packet::Success;
871    return tc->getCpuPtr()->cycles(1);
872}
873
874Tick
875DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
876{
877    uint64_t data = gtoh(pkt->get<uint64_t>());
878    Addr va = pkt->getAddr();
879    ASI asi = (ASI)pkt->req->getAsi();
880
881    Addr ta_insert;
882    Addr va_insert;
883    Addr ct_insert;
884    int part_insert;
885    int entry_insert = -1;
886    bool real_insert;
887    PageTableEntry pte;
888
889    DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
890         (uint32_t)asi, va, data);
891
892    switch (asi) {
893      case ASI_LSU_CONTROL_REG:
894        assert(va == 0);
895        tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
896        break;
897      case ASI_MMU:
898        switch (va) {
899          case 0x8:
900            tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
901            break;
902          case 0x10:
903            tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
904            break;
905          default:
906            goto doMmuWriteError;
907        }
908        break;
909      case ASI_QUEUE:
910        assert(mbits(data,13,6) == data);
911        tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
912                    (va >> 4) - 0x3c, data);
913        break;
914      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
915        assert(va == 0);
916        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
917        break;
918      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
919        assert(va == 0);
920        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
921        break;
922      case ASI_DMMU_CTXT_ZERO_CONFIG:
923        assert(va == 0);
924        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
925        break;
926      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
927        assert(va == 0);
928        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
929        break;
930      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
931        assert(va == 0);
932        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
933        break;
934      case ASI_IMMU_CTXT_ZERO_CONFIG:
935        assert(va == 0);
936        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
937        break;
938      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
939        assert(va == 0);
940        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
941        break;
942      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
943        assert(va == 0);
944        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
945        break;
946      case ASI_DMMU_CTXT_NONZERO_CONFIG:
947        assert(va == 0);
948        tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
949        break;
950      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
951        assert(va == 0);
952        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
953        break;
954      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
955        assert(va == 0);
956        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
957        break;
958      case ASI_IMMU_CTXT_NONZERO_CONFIG:
959        assert(va == 0);
960        tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
961        break;
962      case ASI_SPARC_ERROR_EN_REG:
963      case ASI_SPARC_ERROR_STATUS_REG:
964        warn("Ignoring write to SPARC ERROR regsiter\n");
965        break;
966      case ASI_HYP_SCRATCHPAD:
967      case ASI_SCRATCHPAD:
968        tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
969        break;
970      case ASI_IMMU:
971        switch (va) {
972          case 0x30:
973            tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
974            break;
975          default:
976            goto doMmuWriteError;
977        }
978        break;
979      case ASI_ITLB_DATA_ACCESS_REG:
980        entry_insert = bits(va, 8,3);
981      case ASI_ITLB_DATA_IN_REG:
982        assert(entry_insert != -1 || mbits(va,10,9) == va);
983        ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
984        va_insert = mbits(ta_insert, 63,13);
985        ct_insert = mbits(ta_insert, 12,0);
986        part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
987        real_insert = bits(va, 9,9);
988        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
989                PageTableEntry::sun4u);
990        tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
991                pte, entry_insert);
992        break;
993      case ASI_DTLB_DATA_ACCESS_REG:
994        entry_insert = bits(va, 8,3);
995      case ASI_DTLB_DATA_IN_REG:
996        assert(entry_insert != -1 || mbits(va,10,9) == va);
997        ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
998        va_insert = mbits(ta_insert, 63,13);
999        ct_insert = mbits(ta_insert, 12,0);
1000        part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1001        real_insert = bits(va, 9,9);
1002        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1003                PageTableEntry::sun4u);
1004        insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1005        break;
1006      case ASI_DMMU:
1007        switch (va) {
1008          case 0x30:
1009            tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1010            break;
1011          case 0x80:
1012            tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1013            break;
1014          default:
1015            goto doMmuWriteError;
1016        }
1017        break;
1018      default:
1019doMmuWriteError:
1020        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1021            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1022    }
1023    pkt->result = Packet::Success;
1024    return tc->getCpuPtr()->cycles(1);
1025}
1026
1027void
1028TLB::serialize(std::ostream &os)
1029{
1030    panic("Need to implement serialize tlb for SPARC\n");
1031}
1032
1033void
1034TLB::unserialize(Checkpoint *cp, const std::string &section)
1035{
1036    panic("Need to implement unserialize tlb for SPARC\n");
1037}
1038
1039
1040DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1041
1042BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1043
1044    Param<int> size;
1045
1046END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1047
1048BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1049
1050    INIT_PARAM_DFLT(size, "TLB size", 48)
1051
1052END_INIT_SIM_OBJECT_PARAMS(ITB)
1053
1054
1055CREATE_SIM_OBJECT(ITB)
1056{
1057    return new ITB(getInstanceName(), size);
1058}
1059
1060REGISTER_SIM_OBJECT("SparcITB", ITB)
1061
1062BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1063
1064    Param<int> size;
1065
1066END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1067
1068BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1069
1070    INIT_PARAM_DFLT(size, "TLB size", 64)
1071
1072END_INIT_SIM_OBJECT_PARAMS(DTB)
1073
1074
1075CREATE_SIM_OBJECT(DTB)
1076{
1077    return new DTB(getInstanceName(), size);
1078}
1079
1080REGISTER_SIM_OBJECT("SparcDTB", DTB)
1081}
1082