tlb.cc revision 4996
12SN/A/*
21762SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
292665Ssaidi@eecs.umich.edu */
302SN/A
312SN/A#include <cstring>
322SN/A
332SN/A#include "arch/sparc/asi.hh"
342SN/A#include "arch/sparc/miscregfile.hh"
352SN/A#include "arch/sparc/tlb.hh"
361354SN/A#include "base/bitfield.hh"
371354SN/A#include "base/trace.hh"
382SN/A#include "cpu/thread_context.hh"
392SN/A#include "cpu/base.hh"
405501Snate@binkert.org#include "mem/packet_access.hh"
415546Snate@binkert.org#include "mem/request.hh"
422SN/A#include "params/SparcDTB.hh"
432SN/A#include "params/SparcITB.hh"
442SN/A#include "sim/system.hh"
452SN/A
4656SN/A/* @todo remove some of the magic constants.  -- ali
475769Snate@binkert.org * */
482361SN/Anamespace SparcISA {
491354SN/A
506216Snate@binkert.orgTLB::TLB(const std::string &name, int s)
5156SN/A    : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
522SN/A      cacheValid(false)
535543Ssaidi@eecs.umich.edu{
542SN/A    // To make this work you'll have to change the hypervisor and OS
551354SN/A    if (size > 64)
561354SN/A        fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
572SN/A
582SN/A    tlb = new TlbEntry[size];
592SN/A    std::memset(tlb, 0, sizeof(TlbEntry) * size);
602SN/A
615501Snate@binkert.org    for (int x = 0; x < size; x++)
625501Snate@binkert.org        freeList.push_back(&tlb[x]);
632SN/A
64395SN/A    c0_tsb_ps0 = 0;
652SN/A    c0_tsb_ps1 = 0;
662SN/A    c0_config = 0;
672SN/A    cx_tsb_ps0 = 0;
685769Snate@binkert.org    cx_tsb_ps1 = 0;
695769Snate@binkert.org    cx_config = 0;
705769Snate@binkert.org    sfsr = 0;
715769Snate@binkert.org    tag_access = 0;
725769Snate@binkert.org}
735769Snate@binkert.org
745769Snate@binkert.orgvoid
755769Snate@binkert.orgTLB::clearUsedBits()
765769Snate@binkert.org{
775769Snate@binkert.org    MapIter i;
785769Snate@binkert.org    for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
795769Snate@binkert.org        TlbEntry *t = i->second;
805774Snate@binkert.org        if (!t->pte.locked()) {
815774Snate@binkert.org            t->used = false;
825774Snate@binkert.org            usedEntries--;
835769Snate@binkert.org        }
842SN/A    }
855502Snate@binkert.org}
865502Snate@binkert.org
875502Snate@binkert.org
885503Snate@binkert.orgvoid
895503Snate@binkert.orgTLB::insert(Addr va, int partition_id, int context_id, bool real,
905502Snate@binkert.org        const PageTableEntry& PTE, int entry)
915502Snate@binkert.org{
925502Snate@binkert.org
935502Snate@binkert.org
945502Snate@binkert.org    MapIter i;
955502Snate@binkert.org    TlbEntry *new_entry = NULL;
965502Snate@binkert.org//    TlbRange tr;
975602Snate@binkert.org    int x;
985602Snate@binkert.org
995501Snate@binkert.org    cacheValid = false;
1005543Ssaidi@eecs.umich.edu    va &= ~(PTE.size()-1);
1015543Ssaidi@eecs.umich.edu /*   tr.va = va;
1025769Snate@binkert.org    tr.size = PTE.size() - 1;
1034016Sstever@eecs.umich.edu    tr.contextId = context_id;
1044016Sstever@eecs.umich.edu    tr.partitionId = partition_id;
1054016Sstever@eecs.umich.edu    tr.real = real;
1064016Sstever@eecs.umich.edu*/
1074016Sstever@eecs.umich.edu
1084016Sstever@eecs.umich.edu    DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
1094016Sstever@eecs.umich.edu            va, PTE.paddr(), partition_id, context_id, (int)real, entry);
1104016Sstever@eecs.umich.edu
1114016Sstever@eecs.umich.edu    // Demap any entry that conflicts
1125501Snate@binkert.org    for (x = 0; x < size; x++) {
1135605Snate@binkert.org        if (tlb[x].range.real == real &&
1145605Snate@binkert.org            tlb[x].range.partitionId == partition_id &&
1155605Snate@binkert.org            tlb[x].range.va < va + PTE.size() - 1 &&
1165605Snate@binkert.org            tlb[x].range.va + tlb[x].range.size >= va &&
1175501Snate@binkert.org            (real || tlb[x].range.contextId == context_id ))
1184016Sstever@eecs.umich.edu        {
1195577SSteve.Reinhardt@amd.com            if (tlb[x].valid) {
1205501Snate@binkert.org                freeList.push_front(&tlb[x]);
1215501Snate@binkert.org                DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);
1225501Snate@binkert.org
1235502Snate@binkert.org                tlb[x].valid = false;
1245502Snate@binkert.org                if (tlb[x].used) {
1255605Snate@binkert.org                    tlb[x].used = false;
1265502Snate@binkert.org                    usedEntries--;
1275502Snate@binkert.org                }
1285605Snate@binkert.org                lookupTable.erase(tlb[x].range);
1295605Snate@binkert.org            }
1305605Snate@binkert.org        }
1315577SSteve.Reinhardt@amd.com    }
1325502Snate@binkert.org
1335502Snate@binkert.org
1345502Snate@binkert.org/*
1355502Snate@binkert.org    i = lookupTable.find(tr);
1362SN/A    if (i != lookupTable.end()) {
1375769Snate@binkert.org        i->second->valid = false;
1385769Snate@binkert.org        if (i->second->used) {
1395769Snate@binkert.org            i->second->used = false;
1405769Snate@binkert.org            usedEntries--;
1415769Snate@binkert.org        }
1425769Snate@binkert.org        freeList.push_front(i->second);
1432SN/A        DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
1445769Snate@binkert.org                i->second);
1455769Snate@binkert.org        lookupTable.erase(i);
1465769Snate@binkert.org    }
1475769Snate@binkert.org*/
1485769Snate@binkert.org
1495769Snate@binkert.org    if (entry != -1) {
1502SN/A        assert(entry < size && entry >= 0);
1515769Snate@binkert.org        new_entry = &tlb[entry];
1525769Snate@binkert.org    } else {
1535769Snate@binkert.org        if (!freeList.empty()) {
1545769Snate@binkert.org            new_entry = freeList.front();
1555769Snate@binkert.org        } else {
1565769Snate@binkert.org            x = lastReplaced;
1575769Snate@binkert.org            do {
1585769Snate@binkert.org                ++x;
1595769Snate@binkert.org                if (x == size)
1605769Snate@binkert.org                    x = 0;
1615769Snate@binkert.org                if (x == lastReplaced)
1625769Snate@binkert.org                    goto insertAllLocked;
1635769Snate@binkert.org            } while (tlb[x].pte.locked());
1645769Snate@binkert.org            lastReplaced = x;
1655769Snate@binkert.org            new_entry = &tlb[x];
1665769Snate@binkert.org        }
1675769Snate@binkert.org        /*
1685769Snate@binkert.org        for (x = 0; x < size; x++) {
1695769Snate@binkert.org            if (!tlb[x].valid || !tlb[x].used)  {
1705769Snate@binkert.org                new_entry = &tlb[x];
1715769Snate@binkert.org                break;
1725769Snate@binkert.org            }
1735769Snate@binkert.org        }*/
1745769Snate@binkert.org    }
1755769Snate@binkert.org
1765769Snate@binkert.orginsertAllLocked:
1775769Snate@binkert.org    // Update the last ently if their all locked
1785769Snate@binkert.org    if (!new_entry) {
1795501Snate@binkert.org        new_entry = &tlb[size-1];
1805543Ssaidi@eecs.umich.edu    }
1812SN/A
1822SN/A    freeList.remove(new_entry);
183396SN/A    if (new_entry->valid && new_entry->used)
184396SN/A        usedEntries--;
185396SN/A    if (new_entry->valid)
186396SN/A        lookupTable.erase(new_entry->range);
187396SN/A
1885501Snate@binkert.org
1895543Ssaidi@eecs.umich.edu    assert(PTE.valid());
1905501Snate@binkert.org    new_entry->range.va = va;
1913329Sstever@eecs.umich.edu    new_entry->range.size = PTE.size() - 1;
1923329Sstever@eecs.umich.edu    new_entry->range.partitionId = partition_id;
1933329Sstever@eecs.umich.edu    new_entry->range.contextId = context_id;
1943329Sstever@eecs.umich.edu    new_entry->range.real = real;
1953329Sstever@eecs.umich.edu    new_entry->pte = PTE;
1963329Sstever@eecs.umich.edu    new_entry->used = true;;
1973329Sstever@eecs.umich.edu    new_entry->valid = true;
1983329Sstever@eecs.umich.edu    usedEntries++;
1995543Ssaidi@eecs.umich.edu
200396SN/A
2013329Sstever@eecs.umich.edu
2023329Sstever@eecs.umich.edu    i = lookupTable.insert(new_entry->range, new_entry);
2033329Sstever@eecs.umich.edu    assert(i != lookupTable.end());
2043329Sstever@eecs.umich.edu
2055543Ssaidi@eecs.umich.edu    // If all entries have there used bit set, clear it on them all, but the
2063329Sstever@eecs.umich.edu    // one we just inserted
207396SN/A    if (usedEntries == size) {
208396SN/A        clearUsedBits();
209396SN/A        new_entry->used = true;
2105543Ssaidi@eecs.umich.edu        usedEntries++;
211396SN/A    }
212396SN/A
2135543Ssaidi@eecs.umich.edu}
214396SN/A
215396SN/A
216396SN/ATlbEntry*
217396SN/ATLB::lookup(Addr va, int partition_id, bool real, int context_id, bool
2185543Ssaidi@eecs.umich.edu        update_used)
219396SN/A{
220396SN/A    MapIter i;
221396SN/A    TlbRange tr;
2225543Ssaidi@eecs.umich.edu    TlbEntry *t;
223396SN/A
224396SN/A    DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
225396SN/A            va, partition_id, context_id, real);
2265543Ssaidi@eecs.umich.edu    // Assemble full address structure
227396SN/A    tr.va = va;
2284075Sbinkertn@umich.edu    tr.size = MachineBytes;
2294075Sbinkertn@umich.edu    tr.contextId = context_id;
2304075Sbinkertn@umich.edu    tr.partitionId = partition_id;
231396SN/A    tr.real = real;
232396SN/A
2335543Ssaidi@eecs.umich.edu    // Try to find the entry
2345501Snate@binkert.org    i = lookupTable.find(tr);
2355501Snate@binkert.org    if (i == lookupTable.end()) {
2365543Ssaidi@eecs.umich.edu        DPRINTF(TLB, "TLB: No valid entry found\n");
237396SN/A        return NULL;
238396SN/A    }
2392SN/A
2402SN/A    // Mark the entries used bit and clear other used bits in needed
2412SN/A    t = i->second;
2422SN/A    DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
2435605Snate@binkert.org            t->pte.size());
2445769Snate@binkert.org
245224SN/A    // Update the used bits only if this is a real access (not a fake one from
2464016Sstever@eecs.umich.edu    // virttophys()
2475501Snate@binkert.org    if (!t->used && update_used) {
2485605Snate@binkert.org        t->used = true;
2495501Snate@binkert.org        usedEntries++;
2505501Snate@binkert.org        if (usedEntries == size) {
2515774Snate@binkert.org            clearUsedBits();
2525501Snate@binkert.org            t->used = true;
2535501Snate@binkert.org            usedEntries++;
2544016Sstever@eecs.umich.edu        }
255224SN/A    }
256224SN/A
2575768Snate@binkert.org    return t;
2585768Snate@binkert.org}
259265SN/A
2605501Snate@binkert.orgvoid
2615501Snate@binkert.orgTLB::dumpAll()
2625501Snate@binkert.org{
2635501Snate@binkert.org    MapIter i;
2645501Snate@binkert.org    for (int x = 0; x < size; x++) {
2655501Snate@binkert.org        if (tlb[x].valid) {
2665501Snate@binkert.org           DPRINTFN("%4d:  %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
2675501Snate@binkert.org                   x, tlb[x].range.partitionId, tlb[x].range.contextId,
2685501Snate@binkert.org                   tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
2695501Snate@binkert.org                   tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
2705501Snate@binkert.org        }
2715501Snate@binkert.org    }
2725501Snate@binkert.org}
2735501Snate@binkert.org
2745501Snate@binkert.orgvoid
2755501Snate@binkert.orgTLB::demapPage(Addr va, int partition_id, bool real, int context_id)
2765501Snate@binkert.org{
2775501Snate@binkert.org    TlbRange tr;
2785501Snate@binkert.org    MapIter i;
2795501Snate@binkert.org
2805501Snate@binkert.org    DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
2812SN/A            va, partition_id, context_id, real);
2825769Snate@binkert.org
2832SN/A    cacheValid = false;
2842SN/A
2855769Snate@binkert.org    // Assemble full address structure
2862SN/A    tr.va = va;
2872SN/A    tr.size = MachineBytes;
2885769Snate@binkert.org    tr.contextId = context_id;
2892SN/A    tr.partitionId = partition_id;
2902667Sstever@eecs.umich.edu    tr.real = real;
2915769Snate@binkert.org
2922667Sstever@eecs.umich.edu    // Demap any entry that conflicts
2932SN/A    i = lookupTable.find(tr);
2942SN/A    if (i != lookupTable.end()) {
2952SN/A        DPRINTF(IPR, "TLB: Demapped page\n");
2962SN/A        i->second->valid = false;
2972SN/A        if (i->second->used) {
2982SN/A            i->second->used = false;
2995605Snate@binkert.org            usedEntries--;
3005501Snate@binkert.org        }
3015501Snate@binkert.org        freeList.push_front(i->second);
3022SN/A        lookupTable.erase(i);
3035501Snate@binkert.org    }
3045501Snate@binkert.org}
3055501Snate@binkert.org
3062SN/Avoid
3072SN/ATLB::demapContext(int partition_id, int context_id)
3082SN/A{
309224SN/A    int x;
310224SN/A    DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
311237SN/A            partition_id, context_id);
3125605Snate@binkert.org    cacheValid = false;
313571SN/A    for (x = 0; x < size; x++) {
314571SN/A        if (tlb[x].range.contextId == context_id &&
3152SN/A            tlb[x].range.partitionId == partition_id) {
3162SN/A            if (tlb[x].valid == true) {
3172SN/A                freeList.push_front(&tlb[x]);
318395SN/A            }
3192SN/A            tlb[x].valid = false;
3205605Snate@binkert.org            if (tlb[x].used) {
321265SN/A                tlb[x].used = false;
3222SN/A                usedEntries--;
3232SN/A            }
3242SN/A            lookupTable.erase(tlb[x].range);
3252SN/A        }
3262SN/A    }
3272SN/A}
3282SN/A
329265SN/Avoid
3302SN/ATLB::demapAll(int partition_id)
3312SN/A{
332512SN/A    int x;
333265SN/A    DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
3342SN/A    cacheValid = false;
3355738Snate@binkert.org    for (x = 0; x < size; x++) {
3365738Snate@binkert.org        if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
3375738Snate@binkert.org            if (tlb[x].valid == true){
3382SN/A                freeList.push_front(&tlb[x]);
3395501Snate@binkert.org            }
3402667Sstever@eecs.umich.edu            tlb[x].valid = false;
3412SN/A            if (tlb[x].used) {
3422SN/A                tlb[x].used = false;
3432SN/A                usedEntries--;
3442SN/A            }
3455501Snate@binkert.org            lookupTable.erase(tlb[x].range);
3465501Snate@binkert.org        }
3475501Snate@binkert.org    }
3482SN/A}
3492SN/A
3502SN/Avoid
3512SN/ATLB::invalidateAll()
3521634SN/A{
3531634SN/A    int x;
3541634SN/A    cacheValid = false;
3551634SN/A
3561634SN/A    freeList.clear();
3572SN/A    lookupTable.clear();
3582SN/A    for (x = 0; x < size; x++) {
3592SN/A        if (tlb[x].valid == true)
3602SN/A            freeList.push_back(&tlb[x]);
3612SN/A        tlb[x].valid = false;
3622SN/A        tlb[x].used = false;
3632SN/A    }
3642SN/A    usedEntries = 0;
3655501Snate@binkert.org}
3662SN/A
3675501Snate@binkert.orguint64_t
3682SN/ATLB::TteRead(int entry) {
3692SN/A    if (entry >= size)
3702SN/A        panic("entry: %d\n", entry);
3715502Snate@binkert.org
3725502Snate@binkert.org    assert(entry < size);
3735605Snate@binkert.org    if (tlb[entry].valid)
374217SN/A        return tlb[entry].pte();
375237SN/A    else
3765605Snate@binkert.org        return (uint64_t)-1ll;
3772SN/A}
3782SN/A
3795605Snate@binkert.orguint64_t
3805605Snate@binkert.orgTLB::TagRead(int entry) {
3815605Snate@binkert.org    assert(entry < size);
3825605Snate@binkert.org    uint64_t tag;
3835605Snate@binkert.org    if (!tlb[entry].valid)
3845605Snate@binkert.org        return (uint64_t)-1ll;
3852SN/A
3865605Snate@binkert.org    tag = tlb[entry].range.contextId;
3875605Snate@binkert.org    tag |= tlb[entry].range.va;
3885605Snate@binkert.org    tag |= (uint64_t)tlb[entry].range.partitionId << 61;
3895605Snate@binkert.org    tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
3902SN/A    tag |= (uint64_t)~tlb[entry].pte._size() << 56;
3915605Snate@binkert.org    return tag;
3925605Snate@binkert.org}
3935605Snate@binkert.org
3945605Snate@binkert.orgbool
3955605Snate@binkert.orgTLB::validVirtualAddress(Addr va, bool am)
3965605Snate@binkert.org{
3975605Snate@binkert.org    if (am)
3985605Snate@binkert.org        return true;
3995605Snate@binkert.org    if (va >= StartVAddrHole && va <= EndVAddrHole)
4005605Snate@binkert.org        return false;
4015605Snate@binkert.org    return true;
4025605Snate@binkert.org}
4035605Snate@binkert.org
4045605Snate@binkert.orgvoid
4055605Snate@binkert.orgTLB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi)
4065605Snate@binkert.org{
4075605Snate@binkert.org    if (sfsr & 0x1)
4085605Snate@binkert.org        sfsr = 0x3;
4095605Snate@binkert.org    else
4105605Snate@binkert.org        sfsr = 1;
4115605Snate@binkert.org
4125605Snate@binkert.org    if (write)
4135605Snate@binkert.org        sfsr |= 1 << 2;
4145605Snate@binkert.org    sfsr |= ct << 4;
4155605Snate@binkert.org    if (se)
4165605Snate@binkert.org        sfsr |= 1 << 6;
4175605Snate@binkert.org    sfsr |= ft << 7;
4185605Snate@binkert.org    sfsr |= asi << 16;
4195605Snate@binkert.org}
4205605Snate@binkert.org
4215605Snate@binkert.orgvoid
4225605Snate@binkert.orgTLB::writeTagAccess(Addr va, int context)
4235605Snate@binkert.org{
4245605Snate@binkert.org    DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n",
4255605Snate@binkert.org            va, context, mbits(va, 63,13) | mbits(context,12,0));
4265605Snate@binkert.org
4275605Snate@binkert.org    tag_access = mbits(va, 63,13) | mbits(context,12,0);
4285605Snate@binkert.org}
4295605Snate@binkert.org
4305605Snate@binkert.orgvoid
4315605Snate@binkert.orgITB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi)
4325605Snate@binkert.org{
4335605Snate@binkert.org    DPRINTF(TLB, "TLB: ITB Fault:  w=%d ct=%d ft=%d asi=%d\n",
4345605Snate@binkert.org             (int)write, ct, ft, asi);
4355605Snate@binkert.org    TLB::writeSfsr(write, ct, se, ft, asi);
4365605Snate@binkert.org}
4375605Snate@binkert.org
4385605Snate@binkert.orgvoid
4395605Snate@binkert.orgDTB::writeSfsr(Addr a, bool write, ContextType ct,
4405605Snate@binkert.org        bool se, FaultTypes ft, int asi)
4415605Snate@binkert.org{
4425605Snate@binkert.org    DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
4435605Snate@binkert.org            a, (int)write, ct, ft, asi);
4445605Snate@binkert.org    TLB::writeSfsr(write, ct, se, ft, asi);
4455605Snate@binkert.org    sfar = a;
4465769Snate@binkert.org}
4475605Snate@binkert.org
4485605Snate@binkert.orgFault
4495605Snate@binkert.orgITB::translate(RequestPtr &req, ThreadContext *tc)
4505605Snate@binkert.org{
4515605Snate@binkert.org    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
4525605Snate@binkert.org
4535605Snate@binkert.org    Addr vaddr = req->getVaddr();
4545605Snate@binkert.org    TlbEntry *e;
4555605Snate@binkert.org
4565605Snate@binkert.org    assert(req->getAsi() == ASI_IMPLICIT);
4575605Snate@binkert.org
4585605Snate@binkert.org    DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
4595605Snate@binkert.org            vaddr, req->getSize());
4605605Snate@binkert.org
4615605Snate@binkert.org    // Be fast if we can!
4625605Snate@binkert.org    if (cacheValid && cacheState == tlbdata) {
4635605Snate@binkert.org        if (cacheEntry) {
4645605Snate@binkert.org            if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
4655605Snate@binkert.org                cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
4665605Snate@binkert.org                    req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
4675605Snate@binkert.org                                  vaddr & cacheEntry->pte.size()-1 );
4685605Snate@binkert.org                    return NoFault;
4696982Snate@binkert.org            }
4706982Snate@binkert.org        } else {
4716982Snate@binkert.org            req->setPaddr(vaddr & PAddrImplMask);
4726982Snate@binkert.org            return NoFault;
4736982Snate@binkert.org        }
4746982Snate@binkert.org    }
4756982Snate@binkert.org
4766982Snate@binkert.org    bool hpriv = bits(tlbdata,0,0);
4775605Snate@binkert.org    bool red = bits(tlbdata,1,1);
4785605Snate@binkert.org    bool priv = bits(tlbdata,2,2);
4792SN/A    bool addr_mask = bits(tlbdata,3,3);
4805605Snate@binkert.org    bool lsu_im = bits(tlbdata,4,4);
4812SN/A
4826712Snate@binkert.org    int part_id = bits(tlbdata,15,8);
4835605Snate@binkert.org    int tl = bits(tlbdata,18,16);
4845774Snate@binkert.org    int pri_context = bits(tlbdata,47,32);
4855774Snate@binkert.org    int context;
4865774Snate@binkert.org    ContextType ct;
4875605Snate@binkert.org    int asi;
4885605Snate@binkert.org    bool real = false;
4895605Snate@binkert.org
4905769Snate@binkert.org    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
4915605Snate@binkert.org           priv, hpriv, red, lsu_im, part_id);
4925769Snate@binkert.org
4935605Snate@binkert.org    if (tl > 0) {
4945769Snate@binkert.org        asi = ASI_N;
4955605Snate@binkert.org        ct = Nucleus;
4965605Snate@binkert.org        context = 0;
4975605Snate@binkert.org    } else {
4982SN/A        asi = ASI_P;
4992SN/A        ct = Primary;
5002SN/A        context = pri_context;
5015605Snate@binkert.org    }
5022SN/A
5035605Snate@binkert.org    if ( hpriv || red ) {
5045774Snate@binkert.org        cacheValid = true;
5055774Snate@binkert.org        cacheState = tlbdata;
5065774Snate@binkert.org        cacheEntry = NULL;
5075605Snate@binkert.org        req->setPaddr(vaddr & PAddrImplMask);
5085605Snate@binkert.org        return NoFault;
5095605Snate@binkert.org    }
5105769Snate@binkert.org
5115769Snate@binkert.org    // If the access is unaligned trap
5125605Snate@binkert.org    if (vaddr & 0x3) {
5135769Snate@binkert.org        writeSfsr(false, ct, false, OtherFault, asi);
5145605Snate@binkert.org        return new MemAddressNotAligned;
5155605Snate@binkert.org    }
5165605Snate@binkert.org
5175605Snate@binkert.org    if (addr_mask)
5182SN/A        vaddr = vaddr & VAddrAMask;
5192SN/A
5202SN/A    if (!validVirtualAddress(vaddr, addr_mask)) {
5215605Snate@binkert.org        writeSfsr(false, ct, false, VaOutOfRange, asi);
5222SN/A        return new InstructionAccessException;
5235605Snate@binkert.org    }
5245605Snate@binkert.org
5255774Snate@binkert.org    if (!lsu_im) {
5265774Snate@binkert.org        e = lookup(vaddr, part_id, true);
5275774Snate@binkert.org        real = true;
5285605Snate@binkert.org        context = 0;
5295605Snate@binkert.org    } else {
5305605Snate@binkert.org        e = lookup(vaddr, part_id, false, context);
5315605Snate@binkert.org    }
5325605Snate@binkert.org
5335605Snate@binkert.org    if (e == NULL || !e->valid) {
5345769Snate@binkert.org        writeTagAccess(vaddr, context);
5355769Snate@binkert.org        if (real)
5365605Snate@binkert.org            return new InstructionRealTranslationMiss;
5375769Snate@binkert.org        else
5385605Snate@binkert.org            return new FastInstructionAccessMMUMiss;
5395769Snate@binkert.org    }
5405605Snate@binkert.org
5415605Snate@binkert.org    // were not priviledged accesing priv page
5425605Snate@binkert.org    if (!priv && e->pte.priv()) {
5432SN/A        writeTagAccess(vaddr, context);
5442SN/A        writeSfsr(false, ct, false, PrivViolation, asi);
5455502Snate@binkert.org        return new InstructionAccessException;
5465502Snate@binkert.org    }
5475502Snate@binkert.org
5485502Snate@binkert.org    // cache translation date for next translation
5495502Snate@binkert.org    cacheValid = true;
5505502Snate@binkert.org    cacheState = tlbdata;
5515502Snate@binkert.org    cacheEntry = e;
5525502Snate@binkert.org
5535502Snate@binkert.org    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
5545502Snate@binkert.org                  vaddr & e->pte.size()-1 );
5555502Snate@binkert.org    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
5565502Snate@binkert.org    return NoFault;
5575502Snate@binkert.org}
5585502Snate@binkert.org
5595502Snate@binkert.org
5605502Snate@binkert.org
5615502Snate@binkert.orgFault
5625502Snate@binkert.orgDTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
5635502Snate@binkert.org{
5645502Snate@binkert.org    /* @todo this could really use some profiling and fixing to make it faster! */
5655502Snate@binkert.org    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
5665502Snate@binkert.org    Addr vaddr = req->getVaddr();
5675502Snate@binkert.org    Addr size = req->getSize();
5685502Snate@binkert.org    ASI asi;
5695502Snate@binkert.org    asi = (ASI)req->getAsi();
5705502Snate@binkert.org    bool implicit = false;
5715502Snate@binkert.org    bool hpriv = bits(tlbdata,0,0);
5725502Snate@binkert.org    bool unaligned = (vaddr & size-1);
5735502Snate@binkert.org
5745502Snate@binkert.org    DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
5755502Snate@binkert.org            vaddr, size, asi);
5765502Snate@binkert.org
5775502Snate@binkert.org    if (lookupTable.size() != 64 - freeList.size())
5785502Snate@binkert.org       panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(),
5795502Snate@binkert.org               freeList.size());
5805502Snate@binkert.org    if (asi == ASI_IMPLICIT)
5815502Snate@binkert.org        implicit = true;
5825502Snate@binkert.org
5835605Snate@binkert.org    // Only use the fast path here if there doesn't need to be an unaligned
5842SN/A    // trap later
5851354SN/A    if (!unaligned) {
586        if (hpriv && implicit) {
587            req->setPaddr(vaddr & PAddrImplMask);
588            return NoFault;
589        }
590
591        // Be fast if we can!
592        if (cacheValid &&  cacheState == tlbdata) {
593
594
595
596            if (cacheEntry[0]) {
597                TlbEntry *ce = cacheEntry[0];
598                Addr ce_va = ce->range.va;
599                if (cacheAsi[0] == asi &&
600                    ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
601                    (!write || ce->pte.writable())) {
602                        req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
603                        if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
604                            req->setFlags(req->getFlags() | UNCACHEABLE);
605                        DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
606                        return NoFault;
607                } // if matched
608            } // if cache entry valid
609            if (cacheEntry[1]) {
610                TlbEntry *ce = cacheEntry[1];
611                Addr ce_va = ce->range.va;
612                if (cacheAsi[1] == asi &&
613                    ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
614                    (!write || ce->pte.writable())) {
615                        req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
616                        if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
617                            req->setFlags(req->getFlags() | UNCACHEABLE);
618                        DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
619                        return NoFault;
620                } // if matched
621            } // if cache entry valid
622        }
623    }
624
625    bool red = bits(tlbdata,1,1);
626    bool priv = bits(tlbdata,2,2);
627    bool addr_mask = bits(tlbdata,3,3);
628    bool lsu_dm = bits(tlbdata,5,5);
629
630    int part_id = bits(tlbdata,15,8);
631    int tl = bits(tlbdata,18,16);
632    int pri_context = bits(tlbdata,47,32);
633    int sec_context = bits(tlbdata,63,48);
634
635    bool real = false;
636    ContextType ct = Primary;
637    int context = 0;
638
639    TlbEntry *e;
640
641    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
642           priv, hpriv, red, lsu_dm, part_id);
643
644    if (implicit) {
645        if (tl > 0) {
646            asi = ASI_N;
647            ct = Nucleus;
648            context = 0;
649        } else {
650            asi = ASI_P;
651            ct = Primary;
652            context = pri_context;
653        }
654    } else {
655        // We need to check for priv level/asi priv
656        if (!priv && !hpriv && !AsiIsUnPriv(asi)) {
657            // It appears that context should be Nucleus in these cases?
658            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
659            return new PrivilegedAction;
660        }
661
662        if (!hpriv && AsiIsHPriv(asi)) {
663            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
664            return new DataAccessException;
665        }
666
667        if (AsiIsPrimary(asi)) {
668            context = pri_context;
669            ct = Primary;
670        } else if (AsiIsSecondary(asi)) {
671            context = sec_context;
672            ct = Secondary;
673        } else if (AsiIsNucleus(asi)) {
674            ct = Nucleus;
675            context = 0;
676        } else {  // ????
677            ct = Primary;
678            context = pri_context;
679        }
680    }
681
682    if (!implicit && asi != ASI_P && asi != ASI_S) {
683        if (AsiIsLittle(asi))
684            panic("Little Endian ASIs not supported\n");
685
686        //XXX It's unclear from looking at the documentation how a no fault
687        //load differs from a regular one, other than what happens concerning
688        //nfo and e bits in the TTE
689//        if (AsiIsNoFault(asi))
690//            panic("No Fault ASIs not supported\n");
691
692        if (AsiIsPartialStore(asi))
693            panic("Partial Store ASIs not supported\n");
694
695        if (AsiIsCmt(asi))
696            panic("Cmt ASI registers not implmented\n");
697
698        if (AsiIsInterrupt(asi))
699            goto handleIntRegAccess;
700        if (AsiIsMmu(asi))
701            goto handleMmuRegAccess;
702        if (AsiIsScratchPad(asi))
703            goto handleScratchRegAccess;
704        if (AsiIsQueue(asi))
705            goto handleQueueRegAccess;
706        if (AsiIsSparcError(asi))
707            goto handleSparcErrorRegAccess;
708
709        if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) &&
710                !AsiIsTwin(asi) && !AsiIsBlock(asi) && !AsiIsNoFault(asi))
711            panic("Accessing ASI %#X. Should we?\n", asi);
712    }
713
714    // If the asi is unaligned trap
715    if (unaligned) {
716        writeSfsr(vaddr, false, ct, false, OtherFault, asi);
717        return new MemAddressNotAligned;
718    }
719
720    if (addr_mask)
721        vaddr = vaddr & VAddrAMask;
722
723    if (!validVirtualAddress(vaddr, addr_mask)) {
724        writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi);
725        return new DataAccessException;
726    }
727
728
729    if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {
730        real = true;
731        context = 0;
732    };
733
734    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
735        req->setPaddr(vaddr & PAddrImplMask);
736        return NoFault;
737    }
738
739    e = lookup(vaddr, part_id, real, context);
740
741    if (e == NULL || !e->valid) {
742        writeTagAccess(vaddr, context);
743        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
744        if (real)
745            return new DataRealTranslationMiss;
746        else
747            return new FastDataAccessMMUMiss;
748
749    }
750
751    if (!priv && e->pte.priv()) {
752        writeTagAccess(vaddr, context);
753        writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
754        return new DataAccessException;
755    }
756
757    if (write && !e->pte.writable()) {
758        writeTagAccess(vaddr, context);
759        writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
760        return new FastDataAccessProtection;
761    }
762
763    if (e->pte.nofault() && !AsiIsNoFault(asi)) {
764        writeTagAccess(vaddr, context);
765        writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
766        return new DataAccessException;
767    }
768
769    if (e->pte.sideffect() && AsiIsNoFault(asi)) {
770        writeTagAccess(vaddr, context);
771        writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi);
772        return new DataAccessException;
773    }
774
775
776    if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
777        req->setFlags(req->getFlags() | UNCACHEABLE);
778
779    // cache translation date for next translation
780    cacheState = tlbdata;
781    if (!cacheValid) {
782        cacheEntry[1] = NULL;
783        cacheEntry[0] = NULL;
784    }
785
786    if (cacheEntry[0] != e && cacheEntry[1] != e) {
787        cacheEntry[1] = cacheEntry[0];
788        cacheEntry[0] = e;
789        cacheAsi[1] = cacheAsi[0];
790        cacheAsi[0] = asi;
791        if (implicit)
792            cacheAsi[0] = (ASI)0;
793    }
794    cacheValid = true;
795    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
796                  vaddr & e->pte.size()-1);
797    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
798    return NoFault;
799
800    /** Normal flow ends here. */
801handleIntRegAccess:
802    if (!hpriv) {
803        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
804        if (priv)
805            return new DataAccessException;
806         else
807            return new PrivilegedAction;
808    }
809
810    if (asi == ASI_SWVR_UDB_INTR_W && !write ||
811                    asi == ASI_SWVR_UDB_INTR_R && write) {
812        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
813        return new DataAccessException;
814    }
815
816    goto regAccessOk;
817
818
819handleScratchRegAccess:
820    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
821        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
822        return new DataAccessException;
823    }
824    goto regAccessOk;
825
826handleQueueRegAccess:
827    if (!priv  && !hpriv) {
828        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
829        return new PrivilegedAction;
830    }
831    if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
832        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
833        return new DataAccessException;
834    }
835    goto regAccessOk;
836
837handleSparcErrorRegAccess:
838    if (!hpriv) {
839        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
840        if (priv)
841            return new DataAccessException;
842         else
843            return new PrivilegedAction;
844    }
845    goto regAccessOk;
846
847
848regAccessOk:
849handleMmuRegAccess:
850    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
851    req->setMmapedIpr(true);
852    req->setPaddr(req->getVaddr());
853    return NoFault;
854};
855
856Tick
857DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
858{
859    Addr va = pkt->getAddr();
860    ASI asi = (ASI)pkt->req->getAsi();
861    uint64_t temp;
862
863    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
864         (uint32_t)pkt->req->getAsi(), pkt->getAddr());
865
866    ITB * itb = tc->getITBPtr();
867
868    switch (asi) {
869      case ASI_LSU_CONTROL_REG:
870        assert(va == 0);
871        pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL));
872        break;
873      case ASI_MMU:
874        switch (va) {
875          case 0x8:
876            pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT));
877            break;
878          case 0x10:
879            pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT));
880            break;
881          default:
882            goto doMmuReadError;
883        }
884        break;
885      case ASI_QUEUE:
886        pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
887                    (va >> 4) - 0x3c));
888        break;
889      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
890        assert(va == 0);
891        pkt->set(c0_tsb_ps0);
892        break;
893      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
894        assert(va == 0);
895        pkt->set(c0_tsb_ps1);
896        break;
897      case ASI_DMMU_CTXT_ZERO_CONFIG:
898        assert(va == 0);
899        pkt->set(c0_config);
900        break;
901      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
902        assert(va == 0);
903        pkt->set(itb->c0_tsb_ps0);
904        break;
905      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
906        assert(va == 0);
907        pkt->set(itb->c0_tsb_ps1);
908        break;
909      case ASI_IMMU_CTXT_ZERO_CONFIG:
910        assert(va == 0);
911        pkt->set(itb->c0_config);
912        break;
913      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
914        assert(va == 0);
915        pkt->set(cx_tsb_ps0);
916        break;
917      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
918        assert(va == 0);
919        pkt->set(cx_tsb_ps1);
920        break;
921      case ASI_DMMU_CTXT_NONZERO_CONFIG:
922        assert(va == 0);
923        pkt->set(cx_config);
924        break;
925      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
926        assert(va == 0);
927        pkt->set(itb->cx_tsb_ps0);
928        break;
929      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
930        assert(va == 0);
931        pkt->set(itb->cx_tsb_ps1);
932        break;
933      case ASI_IMMU_CTXT_NONZERO_CONFIG:
934        assert(va == 0);
935        pkt->set(itb->cx_config);
936        break;
937      case ASI_SPARC_ERROR_STATUS_REG:
938        pkt->set((uint64_t)0);
939        break;
940      case ASI_HYP_SCRATCHPAD:
941      case ASI_SCRATCHPAD:
942        pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
943        break;
944      case ASI_IMMU:
945        switch (va) {
946          case 0x0:
947            temp = itb->tag_access;
948            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
949            break;
950          case 0x18:
951            pkt->set(itb->sfsr);
952            break;
953          case 0x30:
954            pkt->set(itb->tag_access);
955            break;
956          default:
957            goto doMmuReadError;
958        }
959        break;
960      case ASI_DMMU:
961        switch (va) {
962          case 0x0:
963            temp = tag_access;
964            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
965            break;
966          case 0x18:
967            pkt->set(sfsr);
968            break;
969          case 0x20:
970            pkt->set(sfar);
971            break;
972          case 0x30:
973            pkt->set(tag_access);
974            break;
975          case 0x80:
976            pkt->set(tc->readMiscReg(MISCREG_MMU_PART_ID));
977            break;
978          default:
979                goto doMmuReadError;
980        }
981        break;
982      case ASI_DMMU_TSB_PS0_PTR_REG:
983        pkt->set(MakeTsbPtr(Ps0,
984            tag_access,
985            c0_tsb_ps0,
986            c0_config,
987            cx_tsb_ps0,
988            cx_config));
989        break;
990      case ASI_DMMU_TSB_PS1_PTR_REG:
991        pkt->set(MakeTsbPtr(Ps1,
992                tag_access,
993                c0_tsb_ps1,
994                c0_config,
995                cx_tsb_ps1,
996                cx_config));
997        break;
998      case ASI_IMMU_TSB_PS0_PTR_REG:
999          pkt->set(MakeTsbPtr(Ps0,
1000                itb->tag_access,
1001                itb->c0_tsb_ps0,
1002                itb->c0_config,
1003                itb->cx_tsb_ps0,
1004                itb->cx_config));
1005        break;
1006      case ASI_IMMU_TSB_PS1_PTR_REG:
1007          pkt->set(MakeTsbPtr(Ps1,
1008                itb->tag_access,
1009                itb->c0_tsb_ps1,
1010                itb->c0_config,
1011                itb->cx_tsb_ps1,
1012                itb->cx_config));
1013        break;
1014      case ASI_SWVR_INTR_RECEIVE:
1015        pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
1016        break;
1017      case ASI_SWVR_UDB_INTR_R:
1018        temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
1019        tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp);
1020        pkt->set(temp);
1021        break;
1022      default:
1023doMmuReadError:
1024        panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1025            (uint32_t)asi, va);
1026    }
1027    pkt->makeAtomicResponse();
1028    return tc->getCpuPtr()->cycles(1);
1029}
1030
1031Tick
1032DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1033{
1034    uint64_t data = gtoh(pkt->get<uint64_t>());
1035    Addr va = pkt->getAddr();
1036    ASI asi = (ASI)pkt->req->getAsi();
1037
1038    Addr ta_insert;
1039    Addr va_insert;
1040    Addr ct_insert;
1041    int part_insert;
1042    int entry_insert = -1;
1043    bool real_insert;
1044    bool ignore;
1045    int part_id;
1046    int ctx_id;
1047    PageTableEntry pte;
1048
1049    DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1050         (uint32_t)asi, va, data);
1051
1052    ITB * itb = tc->getITBPtr();
1053
1054    switch (asi) {
1055      case ASI_LSU_CONTROL_REG:
1056        assert(va == 0);
1057        tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data);
1058        break;
1059      case ASI_MMU:
1060        switch (va) {
1061          case 0x8:
1062            tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data);
1063            break;
1064          case 0x10:
1065            tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data);
1066            break;
1067          default:
1068            goto doMmuWriteError;
1069        }
1070        break;
1071      case ASI_QUEUE:
1072        assert(mbits(data,13,6) == data);
1073        tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
1074                    (va >> 4) - 0x3c, data);
1075        break;
1076      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1077        assert(va == 0);
1078        c0_tsb_ps0 = data;
1079        break;
1080      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1081        assert(va == 0);
1082        c0_tsb_ps1 = data;
1083        break;
1084      case ASI_DMMU_CTXT_ZERO_CONFIG:
1085        assert(va == 0);
1086        c0_config = data;
1087        break;
1088      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1089        assert(va == 0);
1090        itb->c0_tsb_ps0 = data;
1091        break;
1092      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1093        assert(va == 0);
1094        itb->c0_tsb_ps1 = data;
1095        break;
1096      case ASI_IMMU_CTXT_ZERO_CONFIG:
1097        assert(va == 0);
1098        itb->c0_config = data;
1099        break;
1100      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1101        assert(va == 0);
1102        cx_tsb_ps0 = data;
1103        break;
1104      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1105        assert(va == 0);
1106        cx_tsb_ps1 = data;
1107        break;
1108      case ASI_DMMU_CTXT_NONZERO_CONFIG:
1109        assert(va == 0);
1110        cx_config = data;
1111        break;
1112      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1113        assert(va == 0);
1114        itb->cx_tsb_ps0 = data;
1115        break;
1116      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1117        assert(va == 0);
1118        itb->cx_tsb_ps1 = data;
1119        break;
1120      case ASI_IMMU_CTXT_NONZERO_CONFIG:
1121        assert(va == 0);
1122        itb->cx_config = data;
1123        break;
1124      case ASI_SPARC_ERROR_EN_REG:
1125      case ASI_SPARC_ERROR_STATUS_REG:
1126        warn("Ignoring write to SPARC ERROR regsiter\n");
1127        break;
1128      case ASI_HYP_SCRATCHPAD:
1129      case ASI_SCRATCHPAD:
1130        tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1131        break;
1132      case ASI_IMMU:
1133        switch (va) {
1134          case 0x18:
1135            itb->sfsr = data;
1136            break;
1137          case 0x30:
1138            sext<59>(bits(data, 59,0));
1139            itb->tag_access = data;
1140            break;
1141          default:
1142            goto doMmuWriteError;
1143        }
1144        break;
1145      case ASI_ITLB_DATA_ACCESS_REG:
1146        entry_insert = bits(va, 8,3);
1147      case ASI_ITLB_DATA_IN_REG:
1148        assert(entry_insert != -1 || mbits(va,10,9) == va);
1149        ta_insert = itb->tag_access;
1150        va_insert = mbits(ta_insert, 63,13);
1151        ct_insert = mbits(ta_insert, 12,0);
1152        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1153        real_insert = bits(va, 9,9);
1154        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1155                PageTableEntry::sun4u);
1156        tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1157                pte, entry_insert);
1158        break;
1159      case ASI_DTLB_DATA_ACCESS_REG:
1160        entry_insert = bits(va, 8,3);
1161      case ASI_DTLB_DATA_IN_REG:
1162        assert(entry_insert != -1 || mbits(va,10,9) == va);
1163        ta_insert = tag_access;
1164        va_insert = mbits(ta_insert, 63,13);
1165        ct_insert = mbits(ta_insert, 12,0);
1166        part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1167        real_insert = bits(va, 9,9);
1168        pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1169                PageTableEntry::sun4u);
1170        insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1171        break;
1172      case ASI_IMMU_DEMAP:
1173        ignore = false;
1174        ctx_id = -1;
1175        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1176        switch (bits(va,5,4)) {
1177          case 0:
1178            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1179            break;
1180          case 1:
1181            ignore = true;
1182            break;
1183          case 3:
1184            ctx_id = 0;
1185            break;
1186          default:
1187            ignore = true;
1188        }
1189
1190        switch(bits(va,7,6)) {
1191          case 0: // demap page
1192            if (!ignore)
1193                tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1194                        bits(va,9,9), ctx_id);
1195            break;
1196          case 1: //demap context
1197            if (!ignore)
1198                tc->getITBPtr()->demapContext(part_id, ctx_id);
1199            break;
1200          case 2:
1201            tc->getITBPtr()->demapAll(part_id);
1202            break;
1203          default:
1204            panic("Invalid type for IMMU demap\n");
1205        }
1206        break;
1207      case ASI_DMMU:
1208        switch (va) {
1209          case 0x18:
1210            sfsr = data;
1211            break;
1212          case 0x30:
1213            sext<59>(bits(data, 59,0));
1214            tag_access = data;
1215            break;
1216          case 0x80:
1217            tc->setMiscReg(MISCREG_MMU_PART_ID, data);
1218            break;
1219          default:
1220            goto doMmuWriteError;
1221        }
1222        break;
1223      case ASI_DMMU_DEMAP:
1224        ignore = false;
1225        ctx_id = -1;
1226        part_id =  tc->readMiscReg(MISCREG_MMU_PART_ID);
1227        switch (bits(va,5,4)) {
1228          case 0:
1229            ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1230            break;
1231          case 1:
1232            ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
1233            break;
1234          case 3:
1235            ctx_id = 0;
1236            break;
1237          default:
1238            ignore = true;
1239        }
1240
1241        switch(bits(va,7,6)) {
1242          case 0: // demap page
1243            if (!ignore)
1244                demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1245            break;
1246          case 1: //demap context
1247            if (!ignore)
1248                demapContext(part_id, ctx_id);
1249            break;
1250          case 2:
1251            demapAll(part_id);
1252            break;
1253          default:
1254            panic("Invalid type for IMMU demap\n");
1255        }
1256        break;
1257       case ASI_SWVR_INTR_RECEIVE:
1258        int msb;
1259        // clear all the interrupts that aren't set in the write
1260        while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) {
1261            msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data);
1262            tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb);
1263        }
1264        break;
1265      case ASI_SWVR_UDB_INTR_W:
1266            tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
1267            post_interrupt(bits(data,5,0),0);
1268        break;
1269 default:
1270doMmuWriteError:
1271        panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1272            (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1273    }
1274    pkt->makeAtomicResponse();
1275    return tc->getCpuPtr()->cycles(1);
1276}
1277
1278void
1279DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
1280{
1281    uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0);
1282    ITB * itb = tc->getITBPtr();
1283    ptrs[0] = MakeTsbPtr(Ps0, tag_access,
1284                c0_tsb_ps0,
1285                c0_config,
1286                cx_tsb_ps0,
1287                cx_config);
1288    ptrs[1] = MakeTsbPtr(Ps1, tag_access,
1289                c0_tsb_ps1,
1290                c0_config,
1291                cx_tsb_ps1,
1292                cx_config);
1293    ptrs[2] = MakeTsbPtr(Ps0, tag_access,
1294                itb->c0_tsb_ps0,
1295                itb->c0_config,
1296                itb->cx_tsb_ps0,
1297                itb->cx_config);
1298    ptrs[3] = MakeTsbPtr(Ps1, tag_access,
1299                itb->c0_tsb_ps1,
1300                itb->c0_config,
1301                itb->cx_tsb_ps1,
1302                itb->cx_config);
1303}
1304
1305
1306
1307
1308
1309uint64_t
1310DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
1311        uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
1312{
1313    uint64_t tsb;
1314    uint64_t config;
1315
1316    if (bits(tag_access, 12,0) == 0) {
1317        tsb = c0_tsb;
1318        config = c0_config;
1319    } else {
1320        tsb = cX_tsb;
1321        config = cX_config;
1322    }
1323
1324    uint64_t ptr = mbits(tsb,63,13);
1325    bool split = bits(tsb,12,12);
1326    int tsb_size = bits(tsb,3,0);
1327    int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8);
1328
1329    if (ps == Ps1  && split)
1330        ptr |= ULL(1) << (13 + tsb_size);
1331    ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4);
1332
1333    return ptr;
1334}
1335
1336
1337void
1338TLB::serialize(std::ostream &os)
1339{
1340    SERIALIZE_SCALAR(size);
1341    SERIALIZE_SCALAR(usedEntries);
1342    SERIALIZE_SCALAR(lastReplaced);
1343
1344    // convert the pointer based free list into an index based one
1345    int *free_list = (int*)malloc(sizeof(int) * size);
1346    int cntr = 0;
1347    std::list<TlbEntry*>::iterator i;
1348    i = freeList.begin();
1349    while (i != freeList.end()) {
1350        free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry);
1351        i++;
1352    }
1353    SERIALIZE_SCALAR(cntr);
1354    SERIALIZE_ARRAY(free_list,  cntr);
1355
1356    for (int x = 0; x < size; x++) {
1357        nameOut(os, csprintf("%s.PTE%d", name(), x));
1358        tlb[x].serialize(os);
1359    }
1360
1361    SERIALIZE_SCALAR(c0_tsb_ps0);
1362    SERIALIZE_SCALAR(c0_tsb_ps1);
1363    SERIALIZE_SCALAR(c0_config);
1364    SERIALIZE_SCALAR(cx_tsb_ps0);
1365    SERIALIZE_SCALAR(cx_tsb_ps1);
1366    SERIALIZE_SCALAR(cx_config);
1367    SERIALIZE_SCALAR(sfsr);
1368    SERIALIZE_SCALAR(tag_access);
1369}
1370
1371void
1372TLB::unserialize(Checkpoint *cp, const std::string &section)
1373{
1374    int oldSize;
1375
1376    paramIn(cp, section, "size", oldSize);
1377    if (oldSize != size)
1378        panic("Don't support unserializing different sized TLBs\n");
1379    UNSERIALIZE_SCALAR(usedEntries);
1380    UNSERIALIZE_SCALAR(lastReplaced);
1381
1382    int cntr;
1383    UNSERIALIZE_SCALAR(cntr);
1384
1385    int *free_list = (int*)malloc(sizeof(int) * cntr);
1386    freeList.clear();
1387    UNSERIALIZE_ARRAY(free_list,  cntr);
1388    for (int x = 0; x < cntr; x++)
1389        freeList.push_back(&tlb[free_list[x]]);
1390
1391    lookupTable.clear();
1392    for (int x = 0; x < size; x++) {
1393        tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
1394        if (tlb[x].valid)
1395            lookupTable.insert(tlb[x].range, &tlb[x]);
1396
1397    }
1398
1399    UNSERIALIZE_SCALAR(c0_tsb_ps0);
1400    UNSERIALIZE_SCALAR(c0_tsb_ps1);
1401    UNSERIALIZE_SCALAR(c0_config);
1402    UNSERIALIZE_SCALAR(cx_tsb_ps0);
1403    UNSERIALIZE_SCALAR(cx_tsb_ps1);
1404    UNSERIALIZE_SCALAR(cx_config);
1405    UNSERIALIZE_SCALAR(sfsr);
1406    UNSERIALIZE_SCALAR(tag_access);
1407}
1408
1409void
1410DTB::serialize(std::ostream &os)
1411{
1412    TLB::serialize(os);
1413    SERIALIZE_SCALAR(sfar);
1414}
1415
1416void
1417DTB::unserialize(Checkpoint *cp, const std::string &section)
1418{
1419    TLB::unserialize(cp, section);
1420    UNSERIALIZE_SCALAR(sfar);
1421}
1422
1423/* end namespace SparcISA */ }
1424
1425SparcISA::ITB *
1426SparcITBParams::create()
1427{
1428    return new SparcISA::ITB(name, size);
1429}
1430
1431SparcISA::DTB *
1432SparcDTBParams::create()
1433{
1434    return new SparcISA::DTB(name, size);
1435}
1436