diff options
Diffstat (limited to 'src/arch')
30 files changed, 3403 insertions, 1188 deletions
diff --git a/src/arch/SConscript b/src/arch/SConscript index bbe3c4e3a..74be5f8d1 100644 --- a/src/arch/SConscript +++ b/src/arch/SConscript @@ -53,6 +53,7 @@ isa_switch_hdrs = Split(''' isa_traits.hh kernel_stats.hh locked_mem.hh + mmaped_ipr.hh process.hh regfile.hh remote_gdb.hh diff --git a/src/arch/alpha/miscregfile.cc b/src/arch/alpha/miscregfile.cc index 962d4609f..67f6c98e4 100644 --- a/src/arch/alpha/miscregfile.cc +++ b/src/arch/alpha/miscregfile.cc @@ -89,12 +89,26 @@ namespace AlphaISA MiscReg MiscRegFile::readRegWithEffect(int misc_reg, ThreadContext *tc) { + switch(misc_reg) { + case MISCREG_FPCR: + return fpcr; + case MISCREG_UNIQ: + return uniq; + case MISCREG_LOCKFLAG: + return lock_flag; + case MISCREG_LOCKADDR: + return lock_addr; + case MISCREG_INTR: + return intr_flag; #if FULL_SYSTEM - return readIpr(misc_reg, tc); + default: + return readIpr(misc_reg, tc); #else - panic("No faulting misc regs in SE mode!"); - return 0; + default: + panic("No faulting misc regs in SE mode!"); + return 0; #endif + } } void diff --git a/src/arch/alpha/mmaped_ipr.hh b/src/arch/alpha/mmaped_ipr.hh new file mode 100644 index 000000000..2b4ba8745 --- /dev/null +++ b/src/arch/alpha/mmaped_ipr.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __ARCH_ALPHA_MMAPED_IPR_HH__ +#define __ARCH_ALPHA_MMAPED_IPR_HH__ + +/** + * @file + * + * ISA-specific helper functions for memory mapped IPR accesses. + */ + +#include "mem/packet.hh" + + +namespace AlphaISA +{ +inline Tick +handleIprRead(ThreadContext *xc, Packet *pkt) +{ + panic("No handleIprRead implementation in Alpha\n"); +} + + +inline Tick +handleIprWrite(ThreadContext *xc, Packet *pkt) +{ + panic("No handleIprWrite implementation in Alpha\n"); +} + + +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc index af69e45c0..c21bf94f5 100644 --- a/src/arch/alpha/tlb.cc +++ b/src/arch/alpha/tlb.cc @@ -48,589 +48,589 @@ using namespace EV5; namespace AlphaISA { - /////////////////////////////////////////////////////////////////////// - // - // Alpha TLB - // +/////////////////////////////////////////////////////////////////////// +// +// Alpha TLB +// #ifdef DEBUG - bool uncacheBit39 = false; - bool uncacheBit40 = false; +bool uncacheBit39 = false; +bool uncacheBit40 = false; #endif #define MODE2MASK(X) (1 << (X)) - TLB::TLB(const string &name, int s) - : SimObject(name), size(s), nlu(0) - { - table = new PTE[size]; - memset(table, 0, sizeof(PTE[size])); - } +TLB::TLB(const string &name, int s) + : SimObject(name), size(s), nlu(0) +{ + table = new PTE[size]; + memset(table, 0, sizeof(PTE[size])); +} - TLB::~TLB() - { - if (table) - delete [] table; - } +TLB::~TLB() +{ + if (table) + delete [] table; +} - // look up an entry in the TLB - PTE * - TLB::lookup(Addr vpn, uint8_t asn) const - { - // assume not found... - PTE *retval = NULL; - - PageTable::const_iterator i = lookupTable.find(vpn); - if (i != lookupTable.end()) { - while (i->first == vpn) { - int index = i->second; - PTE *pte = &table[index]; - assert(pte->valid); - if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { - retval = pte; - break; - } +// look up an entry in the TLB +PTE * +TLB::lookup(Addr vpn, uint8_t asn) const +{ + // assume not found... + PTE *retval = NULL; - ++i; + PageTable::const_iterator i = lookupTable.find(vpn); + if (i != lookupTable.end()) { + while (i->first == vpn) { + int index = i->second; + PTE *pte = &table[index]; + assert(pte->valid); + if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { + retval = pte; + break; } - } - DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, - retval ? "hit" : "miss", retval ? retval->ppn : 0); - return retval; + ++i; + } } + DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, + retval ? "hit" : "miss", retval ? retval->ppn : 0); + return retval; +} - Fault - TLB::checkCacheability(RequestPtr &req) - { - // in Alpha, cacheability is controlled by upper-level bits of the - // physical address - /* - * We support having the uncacheable bit in either bit 39 or bit 40. - * The Turbolaser platform (and EV5) support having the bit in 39, but - * Tsunami (which Linux assumes uses an EV6) generates accesses with - * the bit in 40. So we must check for both, but we have debug flags - * to catch a weird case where both are used, which shouldn't happen. - */ +Fault +TLB::checkCacheability(RequestPtr &req) +{ +// in Alpha, cacheability is controlled by upper-level bits of the +// physical address + +/* + * We support having the uncacheable bit in either bit 39 or bit 40. + * The Turbolaser platform (and EV5) support having the bit in 39, but + * Tsunami (which Linux assumes uses an EV6) generates accesses with + * the bit in 40. So we must check for both, but we have debug flags + * to catch a weird case where both are used, which shouldn't happen. + */ #if ALPHA_TLASER - if (req->getPaddr() & PAddrUncachedBit39) { + if (req->getPaddr() & PAddrUncachedBit39) { #else - if (req->getPaddr() & PAddrUncachedBit43) { + if (req->getPaddr() & PAddrUncachedBit43) { #endif - // IPR memory space not implemented - if (PAddrIprSpace(req->getPaddr())) { - return new UnimpFault("IPR memory space not implemented!"); - } else { - // mark request as uncacheable - req->setFlags(req->getFlags() | UNCACHEABLE); + // IPR memory space not implemented + if (PAddrIprSpace(req->getPaddr())) { + return new UnimpFault("IPR memory space not implemented!"); + } else { + // mark request as uncacheable + req->setFlags(req->getFlags() | UNCACHEABLE); #if !ALPHA_TLASER - // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) - req->setPaddr(req->getPaddr() & PAddrUncachedMask); + // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) + req->setPaddr(req->getPaddr() & PAddrUncachedMask); #endif - } } - return NoFault; } + return NoFault; +} - // insert a new TLB entry - void - TLB::insert(Addr addr, PTE &pte) - { - VAddr vaddr = addr; - if (table[nlu].valid) { - Addr oldvpn = table[nlu].tag; - PageTable::iterator i = lookupTable.find(oldvpn); - - if (i == lookupTable.end()) - panic("TLB entry not found in lookupTable"); - - int index; - while ((index = i->second) != nlu) { - if (table[index].tag != oldvpn) - panic("TLB entry not found in lookupTable"); +// insert a new TLB entry +void +TLB::insert(Addr addr, PTE &pte) +{ + VAddr vaddr = addr; + if (table[nlu].valid) { + Addr oldvpn = table[nlu].tag; + PageTable::iterator i = lookupTable.find(oldvpn); - ++i; - } + if (i == lookupTable.end()) + panic("TLB entry not found in lookupTable"); - DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); + int index; + while ((index = i->second) != nlu) { + if (table[index].tag != oldvpn) + panic("TLB entry not found in lookupTable"); - lookupTable.erase(i); + ++i; } - DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); + DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); - table[nlu] = pte; - table[nlu].tag = vaddr.vpn(); - table[nlu].valid = true; - - lookupTable.insert(make_pair(vaddr.vpn(), nlu)); - nextnlu(); + lookupTable.erase(i); } - void - TLB::flushAll() - { - DPRINTF(TLB, "flushAll\n"); - memset(table, 0, sizeof(PTE[size])); - lookupTable.clear(); - nlu = 0; - } + DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); - void - TLB::flushProcesses() - { - PageTable::iterator i = lookupTable.begin(); - PageTable::iterator end = lookupTable.end(); - while (i != end) { - int index = i->second; - PTE *pte = &table[index]; - assert(pte->valid); + table[nlu] = pte; + table[nlu].tag = vaddr.vpn(); + table[nlu].valid = true; - // we can't increment i after we erase it, so save a copy and - // increment it to get the next entry now - PageTable::iterator cur = i; - ++i; + lookupTable.insert(make_pair(vaddr.vpn(), nlu)); + nextnlu(); +} - if (!pte->asma) { - DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); - pte->valid = false; - lookupTable.erase(cur); - } +void +TLB::flushAll() +{ + DPRINTF(TLB, "flushAll\n"); + memset(table, 0, sizeof(PTE[size])); + lookupTable.clear(); + nlu = 0; +} + +void +TLB::flushProcesses() +{ + PageTable::iterator i = lookupTable.begin(); + PageTable::iterator end = lookupTable.end(); + while (i != end) { + int index = i->second; + PTE *pte = &table[index]; + assert(pte->valid); + + // we can't increment i after we erase it, so save a copy and + // increment it to get the next entry now + PageTable::iterator cur = i; + ++i; + + if (!pte->asma) { + DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); + pte->valid = false; + lookupTable.erase(cur); } } +} - void - TLB::flushAddr(Addr addr, uint8_t asn) - { - VAddr vaddr = addr; +void +TLB::flushAddr(Addr addr, uint8_t asn) +{ + VAddr vaddr = addr; - PageTable::iterator i = lookupTable.find(vaddr.vpn()); - if (i == lookupTable.end()) - return; + PageTable::iterator i = lookupTable.find(vaddr.vpn()); + if (i == lookupTable.end()) + return; - while (i->first == vaddr.vpn()) { - int index = i->second; - PTE *pte = &table[index]; - assert(pte->valid); - - if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { - DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), - pte->ppn); + while (i->first == vaddr.vpn()) { + int index = i->second; + PTE *pte = &table[index]; + assert(pte->valid); - // invalidate this entry - pte->valid = false; + if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { + DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), + pte->ppn); - lookupTable.erase(i); - } + // invalidate this entry + pte->valid = false; - ++i; + lookupTable.erase(i); } + + ++i; } +} - void - TLB::serialize(ostream &os) - { - SERIALIZE_SCALAR(size); - SERIALIZE_SCALAR(nlu); +void +TLB::serialize(ostream &os) +{ + SERIALIZE_SCALAR(size); + SERIALIZE_SCALAR(nlu); - for (int i = 0; i < size; i++) { - nameOut(os, csprintf("%s.PTE%d", name(), i)); - table[i].serialize(os); - } + for (int i = 0; i < size; i++) { + nameOut(os, csprintf("%s.PTE%d", name(), i)); + table[i].serialize(os); } +} - void - TLB::unserialize(Checkpoint *cp, const string §ion) - { - UNSERIALIZE_SCALAR(size); - UNSERIALIZE_SCALAR(nlu); +void +TLB::unserialize(Checkpoint *cp, const string §ion) +{ + UNSERIALIZE_SCALAR(size); + UNSERIALIZE_SCALAR(nlu); - for (int i = 0; i < size; i++) { - table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); - if (table[i].valid) { - lookupTable.insert(make_pair(table[i].tag, i)); - } + for (int i = 0; i < size; i++) { + table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); + if (table[i].valid) { + lookupTable.insert(make_pair(table[i].tag, i)); } } +} - /////////////////////////////////////////////////////////////////////// - // - // Alpha ITB - // - ITB::ITB(const std::string &name, int size) - : TLB(name, size) - {} - - - void - ITB::regStats() - { - hits - .name(name() + ".hits") - .desc("ITB hits"); - misses - .name(name() + ".misses") - .desc("ITB misses"); - acv - .name(name() + ".acv") - .desc("ITB acv"); - accesses - .name(name() + ".accesses") - .desc("ITB accesses"); - - accesses = hits + misses; - } +/////////////////////////////////////////////////////////////////////// +// +// Alpha ITB +// +ITB::ITB(const std::string &name, int size) + : TLB(name, size) +{} - Fault - ITB::translate(RequestPtr &req, ThreadContext *tc) const - { - if (PcPAL(req->getPC())) { - // strip off PAL PC marker (lsb is 1) - req->setPaddr((req->getVaddr() & ~3) & PAddrImplMask); - hits++; - return NoFault; - } +void +ITB::regStats() +{ + hits + .name(name() + ".hits") + .desc("ITB hits"); + misses + .name(name() + ".misses") + .desc("ITB misses"); + acv + .name(name() + ".acv") + .desc("ITB acv"); + accesses + .name(name() + ".accesses") + .desc("ITB accesses"); + + accesses = hits + misses; +} - if (req->getFlags() & PHYSICAL) { - req->setPaddr(req->getVaddr()); - } else { - // verify that this is a good virtual address - if (!validVirtualAddress(req->getVaddr())) { - acv++; - return new ItbAcvFault(req->getVaddr()); - } +Fault +ITB::translate(RequestPtr &req, ThreadContext *tc) const +{ + if (PcPAL(req->getPC())) { + // strip off PAL PC marker (lsb is 1) + req->setPaddr((req->getVaddr() & ~3) & PAddrImplMask); + hits++; + return NoFault; + } + + if (req->getFlags() & PHYSICAL) { + req->setPaddr(req->getVaddr()); + } else { + // verify that this is a good virtual address + if (!validVirtualAddress(req->getVaddr())) { + acv++; + return new ItbAcvFault(req->getVaddr()); + } - // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 - // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 + + // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 + // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 #if ALPHA_TLASER - if ((MCSR_SP(tc->readMiscReg(IPR_MCSR)) & 2) && - VAddrSpaceEV5(req->getVaddr()) == 2) { + if ((MCSR_SP(tc->readMiscReg(IPR_MCSR)) & 2) && + VAddrSpaceEV5(req->getVaddr()) == 2) { #else - if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { + if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { #endif - // only valid in kernel mode - if (ICM_CM(tc->readMiscReg(IPR_ICM)) != - mode_kernel) { - acv++; - return new ItbAcvFault(req->getVaddr()); - } + // only valid in kernel mode + if (ICM_CM(tc->readMiscReg(IPR_ICM)) != + mode_kernel) { + acv++; + return new ItbAcvFault(req->getVaddr()); + } - req->setPaddr(req->getVaddr() & PAddrImplMask); + req->setPaddr(req->getVaddr() & PAddrImplMask); #if !ALPHA_TLASER - // sign extend the physical address properly - if (req->getPaddr() & PAddrUncachedBit40) - req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); - else - req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); + // sign extend the physical address properly + if (req->getPaddr() & PAddrUncachedBit40) + req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); + else + req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); #endif - } else { - // not a physical address: need to look up pte - int asn = DTB_ASN_ASN(tc->readMiscReg(IPR_DTB_ASN)); - PTE *pte = lookup(VAddr(req->getVaddr()).vpn(), - asn); - - if (!pte) { - misses++; - return new ItbPageFault(req->getVaddr()); - } - - req->setPaddr((pte->ppn << PageShift) + - (VAddr(req->getVaddr()).offset() - & ~3)); + } else { + // not a physical address: need to look up pte + int asn = DTB_ASN_ASN(tc->readMiscReg(IPR_DTB_ASN)); + PTE *pte = lookup(VAddr(req->getVaddr()).vpn(), + asn); + + if (!pte) { + misses++; + return new ItbPageFault(req->getVaddr()); + } - // check permissions for this access - if (!(pte->xre & - (1 << ICM_CM(tc->readMiscReg(IPR_ICM))))) { - // instruction access fault - acv++; - return new ItbAcvFault(req->getVaddr()); - } + req->setPaddr((pte->ppn << PageShift) + + (VAddr(req->getVaddr()).offset() + & ~3)); - hits++; + // check permissions for this access + if (!(pte->xre & + (1 << ICM_CM(tc->readMiscReg(IPR_ICM))))) { + // instruction access fault + acv++; + return new ItbAcvFault(req->getVaddr()); } + + hits++; } + } - // check that the physical address is ok (catch bad physical addresses) - if (req->getPaddr() & ~PAddrImplMask) - return genMachineCheckFault(); + // check that the physical address is ok (catch bad physical addresses) + if (req->getPaddr() & ~PAddrImplMask) + return genMachineCheckFault(); - return checkCacheability(req); + return checkCacheability(req); - } +} - /////////////////////////////////////////////////////////////////////// - // - // Alpha DTB - // - DTB::DTB(const std::string &name, int size) - : TLB(name, size) - {} - - void - DTB::regStats() - { - read_hits - .name(name() + ".read_hits") - .desc("DTB read hits") - ; - - read_misses - .name(name() + ".read_misses") - .desc("DTB read misses") - ; - - read_acv - .name(name() + ".read_acv") - .desc("DTB read access violations") - ; - - read_accesses - .name(name() + ".read_accesses") - .desc("DTB read accesses") - ; - - write_hits - .name(name() + ".write_hits") - .desc("DTB write hits") - ; - - write_misses - .name(name() + ".write_misses") - .desc("DTB write misses") - ; - - write_acv - .name(name() + ".write_acv") - .desc("DTB write access violations") - ; - - write_accesses - .name(name() + ".write_accesses") - .desc("DTB write accesses") - ; - - hits - .name(name() + ".hits") - .desc("DTB hits") - ; - - misses - .name(name() + ".misses") - .desc("DTB misses") - ; - - acv - .name(name() + ".acv") - .desc("DTB access violations") - ; - - accesses - .name(name() + ".accesses") - .desc("DTB accesses") - ; - - hits = read_hits + write_hits; - misses = read_misses + write_misses; - acv = read_acv + write_acv; - accesses = read_accesses + write_accesses; - } +/////////////////////////////////////////////////////////////////////// +// +// Alpha DTB +// + DTB::DTB(const std::string &name, int size) + : TLB(name, size) +{} - Fault - DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) const - { - Addr pc = tc->readPC(); +void +DTB::regStats() +{ + read_hits + .name(name() + ".read_hits") + .desc("DTB read hits") + ; + + read_misses + .name(name() + ".read_misses") + .desc("DTB read misses") + ; + + read_acv + .name(name() + ".read_acv") + .desc("DTB read access violations") + ; + + read_accesses + .name(name() + ".read_accesses") + .desc("DTB read accesses") + ; + + write_hits + .name(name() + ".write_hits") + .desc("DTB write hits") + ; + + write_misses + .name(name() + ".write_misses") + .desc("DTB write misses") + ; + + write_acv + .name(name() + ".write_acv") + .desc("DTB write access violations") + ; + + write_accesses + .name(name() + ".write_accesses") + .desc("DTB write accesses") + ; + + hits + .name(name() + ".hits") + .desc("DTB hits") + ; + + misses + .name(name() + ".misses") + .desc("DTB misses") + ; + + acv + .name(name() + ".acv") + .desc("DTB access violations") + ; + + accesses + .name(name() + ".accesses") + .desc("DTB accesses") + ; + + hits = read_hits + write_hits; + misses = read_misses + write_misses; + acv = read_acv + write_acv; + accesses = read_accesses + write_accesses; +} - mode_type mode = - (mode_type)DTB_CM_CM(tc->readMiscReg(IPR_DTB_CM)); +Fault +DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) const +{ + Addr pc = tc->readPC(); + mode_type mode = + (mode_type)DTB_CM_CM(tc->readMiscReg(IPR_DTB_CM)); - /** - * Check for alignment faults - */ - if (req->getVaddr() & (req->getSize() - 1)) { - DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(), - req->getSize()); - uint64_t flags = write ? MM_STAT_WR_MASK : 0; - return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags); - } - if (pc & 0x1) { - mode = (req->getFlags() & ALTMODE) ? - (mode_type)ALT_MODE_AM( - tc->readMiscReg(IPR_ALT_MODE)) - : mode_kernel; - } + /** + * Check for alignment faults + */ + if (req->getVaddr() & (req->getSize() - 1)) { + DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(), + req->getSize()); + uint64_t flags = write ? MM_STAT_WR_MASK : 0; + return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags); + } - if (req->getFlags() & PHYSICAL) { - req->setPaddr(req->getVaddr()); - } else { - // verify that this is a good virtual address - if (!validVirtualAddress(req->getVaddr())) { - if (write) { write_acv++; } else { read_acv++; } - uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | - MM_STAT_BAD_VA_MASK | - MM_STAT_ACV_MASK; - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); - } + if (PcPAL(pc)) { + mode = (req->getFlags() & ALTMODE) ? + (mode_type)ALT_MODE_AM( + tc->readMiscReg(IPR_ALT_MODE)) + : mode_kernel; + } - // Check for "superpage" mapping + if (req->getFlags() & PHYSICAL) { + req->setPaddr(req->getVaddr()); + } else { + // verify that this is a good virtual address + if (!validVirtualAddress(req->getVaddr())) { + if (write) { write_acv++; } else { read_acv++; } + uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_BAD_VA_MASK | + MM_STAT_ACV_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + + // Check for "superpage" mapping #if ALPHA_TLASER - if ((MCSR_SP(tc->readMiscReg(IPR_MCSR)) & 2) && - VAddrSpaceEV5(req->getVaddr()) == 2) { + if ((MCSR_SP(tc->readMiscReg(IPR_MCSR)) & 2) && + VAddrSpaceEV5(req->getVaddr()) == 2) { #else - if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { + if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { #endif - // only valid in kernel mode - if (DTB_CM_CM(tc->readMiscReg(IPR_DTB_CM)) != - mode_kernel) { - if (write) { write_acv++; } else { read_acv++; } - uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | - MM_STAT_ACV_MASK); - return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); - } + // only valid in kernel mode + if (DTB_CM_CM(tc->readMiscReg(IPR_DTB_CM)) != + mode_kernel) { + if (write) { write_acv++; } else { read_acv++; } + uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | + MM_STAT_ACV_MASK); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + } - req->setPaddr(req->getVaddr() & PAddrImplMask); + req->setPaddr(req->getVaddr() & PAddrImplMask); #if !ALPHA_TLASER - // sign extend the physical address properly - if (req->getPaddr() & PAddrUncachedBit40) - req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); - else - req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); + // sign extend the physical address properly + if (req->getPaddr() & PAddrUncachedBit40) + req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); + else + req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); #endif + } else { + if (write) + write_accesses++; + else + read_accesses++; + + int asn = DTB_ASN_ASN(tc->readMiscReg(IPR_DTB_ASN)); + + // not a physical address: need to look up pte + PTE *pte = lookup(VAddr(req->getVaddr()).vpn(), + asn); + + if (!pte) { + // page fault + if (write) { write_misses++; } else { read_misses++; } + uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_DTB_MISS_MASK; + return (req->getFlags() & VPTE) ? + (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(), + flags)) : + (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(), + flags)); + } + + req->setPaddr((pte->ppn << PageShift) + + VAddr(req->getVaddr()).offset()); + + if (write) { + if (!(pte->xwe & MODE2MASK(mode))) { + // declare the instruction access fault + write_acv++; + uint64_t flags = MM_STAT_WR_MASK | + MM_STAT_ACV_MASK | + (pte->fonw ? MM_STAT_FONW_MASK : 0); + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + if (pte->fonw) { + write_acv++; + uint64_t flags = MM_STAT_WR_MASK | + MM_STAT_FONW_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } } else { - if (write) - write_accesses++; - else - read_accesses++; - - int asn = DTB_ASN_ASN(tc->readMiscReg(IPR_DTB_ASN)); - - // not a physical address: need to look up pte - PTE *pte = lookup(VAddr(req->getVaddr()).vpn(), - asn); - - if (!pte) { - // page fault - if (write) { write_misses++; } else { read_misses++; } - uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | - MM_STAT_DTB_MISS_MASK; - return (req->getFlags() & VPTE) ? - (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(), - flags)) : - (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(), - flags)); + if (!(pte->xre & MODE2MASK(mode))) { + read_acv++; + uint64_t flags = MM_STAT_ACV_MASK | + (pte->fonr ? MM_STAT_FONR_MASK : 0); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); } - - req->setPaddr((pte->ppn << PageShift) + - VAddr(req->getVaddr()).offset()); - - if (write) { - if (!(pte->xwe & MODE2MASK(mode))) { - // declare the instruction access fault - write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_ACV_MASK | - (pte->fonw ? MM_STAT_FONW_MASK : 0); - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); - } - if (pte->fonw) { - write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_FONW_MASK; - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); - } - } else { - if (!(pte->xre & MODE2MASK(mode))) { - read_acv++; - uint64_t flags = MM_STAT_ACV_MASK | - (pte->fonr ? MM_STAT_FONR_MASK : 0); - return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); - } - if (pte->fonr) { - read_acv++; - uint64_t flags = MM_STAT_FONR_MASK; - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); - } + if (pte->fonr) { + read_acv++; + uint64_t flags = MM_STAT_FONR_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); } } - - if (write) - write_hits++; - else - read_hits++; } - // check that the physical address is ok (catch bad physical addresses) - if (req->getPaddr() & ~PAddrImplMask) - return genMachineCheckFault(); - - return checkCacheability(req); + if (write) + write_hits++; + else + read_hits++; } - PTE & - TLB::index(bool advance) - { - PTE *pte = &table[nlu]; + // check that the physical address is ok (catch bad physical addresses) + if (req->getPaddr() & ~PAddrImplMask) + return genMachineCheckFault(); - if (advance) - nextnlu(); + return checkCacheability(req); +} - return *pte; - } +PTE & +TLB::index(bool advance) +{ + PTE *pte = &table[nlu]; + + if (advance) + nextnlu(); - DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", TLB) + return *pte; +} - BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB) +DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", TLB) - Param<int> size; +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB) - END_DECLARE_SIM_OBJECT_PARAMS(ITB) + Param<int> size; - BEGIN_INIT_SIM_OBJECT_PARAMS(ITB) +END_DECLARE_SIM_OBJECT_PARAMS(ITB) - INIT_PARAM_DFLT(size, "TLB size", 48) +BEGIN_INIT_SIM_OBJECT_PARAMS(ITB) - END_INIT_SIM_OBJECT_PARAMS(ITB) + INIT_PARAM_DFLT(size, "TLB size", 48) +END_INIT_SIM_OBJECT_PARAMS(ITB) - CREATE_SIM_OBJECT(ITB) - { - return new ITB(getInstanceName(), size); - } - REGISTER_SIM_OBJECT("AlphaITB", ITB) +CREATE_SIM_OBJECT(ITB) +{ + return new ITB(getInstanceName(), size); +} - BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB) +REGISTER_SIM_OBJECT("AlphaITB", ITB) - Param<int> size; +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB) - END_DECLARE_SIM_OBJECT_PARAMS(DTB) + Param<int> size; - BEGIN_INIT_SIM_OBJECT_PARAMS(DTB) +END_DECLARE_SIM_OBJECT_PARAMS(DTB) - INIT_PARAM_DFLT(size, "TLB size", 64) +BEGIN_INIT_SIM_OBJECT_PARAMS(DTB) - END_INIT_SIM_OBJECT_PARAMS(DTB) + INIT_PARAM_DFLT(size, "TLB size", 64) +END_INIT_SIM_OBJECT_PARAMS(DTB) - CREATE_SIM_OBJECT(DTB) - { - return new DTB(getInstanceName(), size); - } - REGISTER_SIM_OBJECT("AlphaDTB", DTB) +CREATE_SIM_OBJECT(DTB) +{ + return new DTB(getInstanceName(), size); +} + +REGISTER_SIM_OBJECT("AlphaDTB", DTB) } diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index aacdf455f..5f6a33565 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -1362,7 +1362,7 @@ class ControlRegOperand(Operand): bit_select = 0 if (self.ctype == 'float' or self.ctype == 'double'): error(0, 'Attempt to read control register as FP') - base = 'xc->readMiscRegOperand(this, %s)' % self.src_reg_idx + base = 'xc->readMiscRegOperandWithEffect(%s)' % self.reg_spec if self.size == self.dflt_size: return '%s = %s;\n' % (self.base_name, base) else: diff --git a/src/arch/mips/mmaped_ipr.hh b/src/arch/mips/mmaped_ipr.hh new file mode 100644 index 000000000..fa82a645c --- /dev/null +++ b/src/arch/mips/mmaped_ipr.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __ARCH_MIPS_MMAPED_IPR_HH__ +#define __ARCH_MIPS_MMAPED_IPR_HH__ + +/** + * @file + * + * ISA-specific helper functions for memory mapped IPR accesses. + */ + +#include "base/misc.hh" +#include "mem/packet.hh" + +class ThreadContext; + +namespace MipsISA +{ +inline Tick +handleIprRead(ThreadContext *xc, Packet *pkt) +{ + panic("No implementation for handleIprRead in MIPS\n"); +} + +inline Tick +handleIprWrite(ThreadContext *xc, Packet *pkt) +{ + panic("No implementation for handleIprWrite in MIPS\n"); +} + + +} // namespace MipsISA + +#endif diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript index 281c166c0..c2ef97bfa 100644 --- a/src/arch/sparc/SConscript +++ b/src/arch/sparc/SConscript @@ -56,9 +56,11 @@ base_sources = Split(''' full_system_sources = Split(''' arguments.cc remote_gdb.cc + pagetable.cc stacktrace.cc system.cc tlb.cc + ua2005.cc vtophys.cc ''') diff --git a/src/arch/sparc/asi.cc b/src/arch/sparc/asi.cc index 00c9e041e..a9a778ff6 100644 --- a/src/arch/sparc/asi.cc +++ b/src/arch/sparc/asi.cc @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black + * Ali Saidi */ #include "arch/sparc/asi.hh" @@ -37,8 +38,8 @@ namespace SparcISA return (asi == ASI_BLK_AIUP) || (asi == ASI_BLK_AIUS) || - (asi == ASI_BLK_AIUPL) || - (asi == ASI_BLK_AIUSL) || + (asi == ASI_BLK_AIUP_L) || + (asi == ASI_BLK_AIUS_L) || (asi == ASI_BLK_P) || (asi == ASI_BLK_S) || (asi == ASI_BLK_PL) || @@ -50,10 +51,10 @@ namespace SparcISA return (asi == ASI_AIUP) || (asi == ASI_BLK_AIUP) || - (asi == ASI_AIUPL) || - (asi == ASI_BLK_AIUPL) || + (asi == ASI_AIUP_L) || + (asi == ASI_BLK_AIUP_L) || (asi == ASI_LDTX_AIUP) || - (asi == ASI_LDTX_AIUPL) || + (asi == ASI_LDTX_AIUP_L) || (asi == ASI_P) || (asi == ASI_PNF) || (asi == ASI_PL) || @@ -79,10 +80,10 @@ namespace SparcISA return (asi == ASI_AIUS) || (asi == ASI_BLK_AIUS) || - (asi == ASI_AIUSL) || - (asi == ASI_BLK_AIUSL) || + (asi == ASI_AIUS_L) || + (asi == ASI_BLK_AIUS_L) || (asi == ASI_LDTX_AIUS) || - (asi == ASI_LDTX_AIUSL) || + (asi == ASI_LDTX_AIUS_L) || (asi == ASI_S) || (asi == ASI_SNF) || (asi == ASI_SL) || @@ -103,7 +104,7 @@ namespace SparcISA (asi == ASI_BLK_SL); } - bool AsiNucleus(ASI asi) + bool AsiIsNucleus(ASI asi) { return (asi == ASI_N) || @@ -119,14 +120,14 @@ namespace SparcISA (asi == ASI_AIUS) || (asi == ASI_BLK_AIUP) || (asi == ASI_BLK_AIUS) || - (asi == ASI_AIUPL) || - (asi == ASI_AIUSL) || - (asi == ASI_BLK_AIUPL) || - (asi == ASI_BLK_AIUSL) || + (asi == ASI_AIUP_L) || + (asi == ASI_AIUS_L) || + (asi == ASI_BLK_AIUP_L) || + (asi == ASI_BLK_AIUS_L) || (asi == ASI_LDTX_AIUP) || (asi == ASI_LDTX_AIUS) || - (asi == ASI_LDTX_AIUPL) || - (asi == ASI_LDTX_AIUSL); + (asi == ASI_LDTX_AIUP_L) || + (asi == ASI_LDTX_AIUS_L); } bool AsiIsIO(ASI asi) @@ -144,22 +145,21 @@ namespace SparcISA (asi == ASI_REAL_L) || (asi == ASI_REAL_IO_L) || (asi == ASI_LDTX_REAL) || - (asi == ASI_LDTX_REAL_L) || - (asi == ASI_MMU_REAL); + (asi == ASI_LDTX_REAL_L); } bool AsiIsLittle(ASI asi) { return (asi == ASI_NL) || - (asi == ASI_AIUPL) || - (asi == ASI_AIUSL) || + (asi == ASI_AIUP_L) || + (asi == ASI_AIUS_L) || (asi == ASI_REAL_L) || (asi == ASI_REAL_IO_L) || - (asi == ASI_BLK_AIUPL) || - (asi == ASI_BLK_AIUSL) || - (asi == ASI_LDTX_AIUPL) || - (asi == ASI_LDTX_AIUSL) || + (asi == ASI_BLK_AIUP_L) || + (asi == ASI_BLK_AIUS_L) || + (asi == ASI_LDTX_AIUP_L) || + (asi == ASI_LDTX_AIUS_L) || (asi == ASI_LDTX_REAL_L) || (asi == ASI_LDTX_NL) || (asi == ASI_PL) || @@ -185,18 +185,20 @@ namespace SparcISA bool AsiIsTwin(ASI asi) { return + (asi == ASI_QUAD_LDD) || (asi == ASI_LDTX_AIUP) || (asi == ASI_LDTX_AIUS) || (asi == ASI_LDTX_REAL) || (asi == ASI_LDTX_N) || - (asi == ASI_LDTX_AIUPL) || - (asi == ASI_LDTX_AIUSL) || + (asi == ASI_LDTX_AIUP_L) || + (asi == ASI_LDTX_AIUS_L) || (asi == ASI_LDTX_REAL_L) || (asi == ASI_LDTX_NL) || (asi == ASI_LDTX_P) || (asi == ASI_LDTX_S) || (asi == ASI_LDTX_PL) || - (asi == ASI_LDTX_SL); + (asi == ASI_LDTX_SL) || + (asi == ASI_LTX_L); } bool AsiIsPartialStore(ASI asi) @@ -248,8 +250,7 @@ namespace SparcISA bool AsiIsCmt(ASI asi) { return - (asi == ASI_CMT_PER_STRAND) || - (asi == ASI_CMT_SHARED); + (asi == ASI_CMT_PER_STRAND); } bool AsiIsQueue(ASI asi) @@ -257,23 +258,52 @@ namespace SparcISA return asi == ASI_QUEUE; } - bool AsiIsDtlb(ASI asi) + bool AsiIsInterrupt(ASI asi) { - return - (asi == ASI_DTLB_DATA_IN_REG) || - (asi == ASI_DTLB_DATA_ACCESS_REG) || - (asi == ASI_DTLB_TAG_READ_REG); + return asi == ASI_SWVR_INTR_RECEIVE || + asi == ASI_SWVR_UDB_INTR_W || + asi == ASI_SWVR_UDB_INTR_R ; } bool AsiIsMmu(ASI asi) { - return - (asi == ASI_MMU_CONTEXTID) || - (asi == ASI_IMMU) || - (asi == ASI_MMU_REAL) || - (asi == ASI_MMU) || - (asi == ASI_DMMU) || - (asi == ASI_UMMU) || - (asi == ASI_DMMU_DEMAP); + return asi == ASI_MMU || + asi == ASI_LSU_CONTROL_REG || + (asi >= ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0 && + asi <= ASI_IMMU_CTXT_ZERO_CONFIG) || + (asi >= ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0 && + asi <= ASI_IMMU_CTXT_NONZERO_CONFIG) || + (asi >= ASI_IMMU && + asi <= ASI_IMMU_TSB_PS1_PTR_REG) || + (asi >= ASI_ITLB_DATA_IN_REG && + asi <= ASI_TLB_INVALIDATE_ALL); } + + bool AsiIsUnPriv(ASI asi) + { + return asi >= 0x80; + } + + bool AsiIsPriv(ASI asi) + { + return asi <= 0x2f; + } + + + bool AsiIsHPriv(ASI asi) + { + return asi >= 0x30 && asi <= 0x7f; + } + + bool AsiIsReg(ASI asi) + { + return AsiIsMmu(asi) || AsiIsScratchPad(asi) | AsiIsSparcError(asi); + } + + bool AsiIsSparcError(ASI asi) + { + return asi == ASI_SPARC_ERROR_EN_REG || + asi == ASI_SPARC_ERROR_STATUS_REG; + } + } diff --git a/src/arch/sparc/asi.hh b/src/arch/sparc/asi.hh index 6677b23df..166c3867e 100644 --- a/src/arch/sparc/asi.hh +++ b/src/arch/sparc/asi.hh @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black + * Ali Saidi */ #ifndef __ARCH_SPARC_ASI_HH__ @@ -34,6 +35,7 @@ namespace SparcISA { enum ASI { + ASI_IMPLICIT = 0x00, /* Priveleged ASIs */ //0x00-0x03 implementation dependent ASI_NUCLEUS = 0x4, @@ -53,64 +55,110 @@ namespace SparcISA ASI_BLOCK_AS_IF_USER_PRIMARY = ASI_BLK_AIUP, ASI_BLK_AIUS = 0x17, ASI_BLOCK_AS_IF_USER_SECONDARY = ASI_BLK_AIUS, - ASI_AIUPL = 0x18, - ASI_AS_IF_USER_PRIMARY_LITTLE = ASI_AIUPL, - ASI_AIUSL = 0x19, - ASI_AS_IF_USER_SECONDARY_LITTLE = ASI_AIUSL, + ASI_AIUP_L = 0x18, + ASI_AS_IF_USER_PRIMARY_LITTLE = ASI_AIUP_L, + ASI_AIUS_L = 0x19, + ASI_AS_IF_USER_SECONDARY_LITTLE = ASI_AIUS_L, //0x1A-0x1B implementation dependent ASI_REAL_L = 0x1C, ASI_REAL_LITTLE = ASI_REAL_L, ASI_REAL_IO_L = 0x1D, ASI_REAL_IO_LITTLE = ASI_REAL_IO_L, - ASI_BLK_AIUPL = 0x1E, - ASI_BLOCK_AS_IF_USER_PRIMARY_LITTLE = ASI_BLK_AIUPL, - ASI_BLK_AIUSL = 0x1F, - ASI_BLOCK_AS_IF_USER_SECONDARY_LITTLE = ASI_BLK_AIUSL, + ASI_BLK_AIUP_L = 0x1E, + ASI_BLOCK_AS_IF_USER_PRIMARY_LITTLE = ASI_BLK_AIUP_L, + ASI_BLK_AIUS_L = 0x1F, + ASI_BLOCK_AS_IF_USER_SECONDARY_LITTLE = ASI_BLK_AIUS_L, ASI_SCRATCHPAD = 0x20, - ASI_MMU_CONTEXTID = 0x21, + ASI_MMU = 0x21, ASI_LDTX_AIUP = 0x22, ASI_LD_TWINX_AS_IF_USER_PRIMARY = ASI_LDTX_AIUP, ASI_LDTX_AIUS = 0x23, ASI_LD_TWINX_AS_IF_USER_SECONDARY = ASI_LDTX_AIUS, - //0x24 implementation dependent + ASI_QUAD_LDD = 0x24, ASI_QUEUE = 0x25, - ASI_LDTX_REAL = 0x26, - ASI_LD_TWINX_REAL = ASI_LDTX_REAL, + ASI_QUAD_LDD_REAL = 0x26, + ASI_LDTX_REAL = ASI_QUAD_LDD_REAL, ASI_LDTX_N = 0x27, ASI_LD_TWINX_NUCLEUS = ASI_LDTX_N, + ASI_ST_BLKINIT_NUCLEUS = ASI_LDTX_N, + ASI_STBI_N = ASI_LDTX_N, //0x28-0x29 implementation dependent - ASI_LDTX_AIUPL = 0x2A, - ASI_LD_TWINX_AS_IF_USER_PRIMARY_LITTLE = ASI_LDTX_AIUPL, - ASI_LDTX_AIUSL = 0x2B, - ASI_LD_TWINX_AS_IF_USER_SECONDARY_LITTLE = ASI_LDTX_AIUSL, - //0x2C-0x2D implementation dependent + ASI_LDTX_AIUP_L = 0x2A, + ASI_TWINX_AS_IF_USER_PRIMARY_LITTLE = ASI_LDTX_AIUP_L, + ASI_ST_BLKINIT_AS_IF_USER_PRIMARY_LITTLE = ASI_LDTX_AIUP_L, + ASI_STBI_AIUP_L = ASI_LDTX_AIUP_L, + ASI_LDTX_AIUS_L = 0x2B, + ASI_LD_TWINX_AS_IF_USER_SECONDARY_LITTLE = ASI_LDTX_AIUS_L, + ASI_ST_BLKINIT_AS_IF_USER_SECONDARY_LITTLE = ASI_LDTX_AIUS_L, + ASI_STBI_AIUS_L = ASI_LDTX_AIUS_L, + ASI_LTX_L = 0x2C, + ASI_TWINX_LITTLE = ASI_LTX_L, + //0x2D implementation dependent ASI_LDTX_REAL_L = 0x2E, ASI_LD_TWINX_REAL_LITTLE = ASI_LDTX_REAL_L, ASI_LDTX_NL = 0x2F, ASI_LD_TWINX_NUCLEUS_LITTLE = ASI_LDTX_NL, - //0x30-0x40 implementation dependent - ASI_CMT_SHARED = 0x41, - //0x42-0x4F implementation dependent + //0x20 implementation dependent + ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0 = 0x31, + ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1 = 0x32, + ASI_DMMU_CTXT_ZERO_CONFIG = 0x33, + //0x34 implementation dependent + ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0 = 0x35, + ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1 = 0x36, + ASI_IMMU_CTXT_ZERO_CONFIG = 0x37, + //0x38 implementation dependent + ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0 = 0x39, + ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1 = 0x3A, + ASI_DMMU_CTXT_NONZERO_CONFIG = 0x3B, + //0x3C implementation dependent + ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0 = 0x3D, + ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1 = 0x3E, + ASI_IMMU_CTXT_NONZERO_CONFIG = 0x3F, + ASI_STREAM_MA = 0x40, + //0x41 implementation dependent + ASI_SPARC_BIST_CONTROL = 0x42, + ASI_INST_MASK_REG = 0x42, + ASI_LSU_DIAG_REG = 0x42, + //0x43 implementation dependent + ASI_STM_CTL_REG = 0x44, + ASI_LSU_CONTROL_REG = 0x45, + ASI_DCACHE_DATA = 0x46, + ASI_DCACHE_TAG = 0x47, + ASI_INTR_DISPATCH_STATUS = 0x48, + ASI_INTR_RECEIVE = 0x49, + ASI_UPA_CONFIG_REGISTER = 0x4A, + ASI_SPARC_ERROR_EN_REG = 0x4B, + ASI_SPARC_ERROR_STATUS_REG = 0x4C, + ASI_SPARC_ERROR_ADDRESS_REG = 0x4D, + ASI_ECACHE_TAG_DATA = 0x4E, ASI_HYP_SCRATCHPAD = 0x4F, ASI_IMMU = 0x50, - ASI_MMU_REAL = 0x52, + ASI_IMMU_TSB_PS0_PTR_REG = 0x51, + ASI_IMMU_TSB_PS1_PTR_REG = 0x52, //0x53 implementation dependent - ASI_MMU = 0x54, + ASI_ITLB_DATA_IN_REG = 0x54, ASI_ITLB_DATA_ACCESS_REG = 0x55, ASI_ITLB_TAG_READ_REG = 0x56, ASI_IMMU_DEMAP = 0x57, ASI_DMMU = 0x58, - ASI_UMMU = 0x58, - //0x59-0x5B reserved + ASI_DMMU_TSB_PS0_PTR_REG = 0x59, + ASI_DMMU_TSB_PS1_PTR_REG = 0x5A, + ASI_DMMU_TSB_DIRECT_PTR_REG = 0x5B, ASI_DTLB_DATA_IN_REG = 0x5C, ASI_DTLB_DATA_ACCESS_REG = 0x5D, ASI_DTLB_TAG_READ_REG = 0x5E, ASI_DMMU_DEMAP = 0x5F, - //0x60-62 implementation dependent + ASI_TLB_INVALIDATE_ALL = 0x60, + //0x61-0x62 implementation dependent ASI_CMT_PER_STRAND = 0x63, - //0x64-0x67 implementation dependent - //0x68-0x7F reserved - + //0x64-0x65 implementation dependent + ASI_ICACHE_INSTR = 0x66, + ASI_ICACHE_TAG = 0x67, + //0x68-0x71 implementation dependent + ASI_SWVR_INTR_RECEIVE = 0x72, + ASI_SWVR_UDB_INTR_W = 0x73, + ASI_SWVR_UDB_INTR_R = 0x74, + //0x74-0x7F reserved /* Unpriveleged ASIs */ ASI_P = 0x80, ASI_PRIMARY = ASI_P, @@ -216,7 +264,12 @@ namespace SparcISA bool AsiIsQueue(ASI); bool AsiIsDtlb(ASI); bool AsiIsMmu(ASI); - + bool AsiIsUnPriv(ASI); + bool AsiIsPriv(ASI); + bool AsiIsHPriv(ASI); + bool AsiIsReg(ASI); + bool AsiIsInterrupt(ASI); + bool AsiIsSparcError(ASI); }; #endif // __ARCH_SPARC_ASI_HH__ diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 4326e8b67..92fdbfdbb 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -532,7 +532,7 @@ void getPrivVector(ThreadContext * tc, Addr & PC, Addr & NPC, MiscReg TT, MiscRe void SparcFaultBase::invoke(ThreadContext * tc) { - panic("Invoking a second fault!\n"); + //panic("Invoking a second fault!\n"); FaultBase::invoke(tc); countStat()++; @@ -555,33 +555,26 @@ void SparcFaultBase::invoke(ThreadContext * tc) PrivilegeLevel level = getNextLevel(current); - if(HPSTATE & (1 << 5) || TL == MaxTL - 1) - { + if(HPSTATE & (1 << 5) || TL == MaxTL - 1) { getREDVector(5, PC, NPC); doREDFault(tc, TT); //This changes the hpstate and pstate, so we need to make sure we //save the old version on the trap stack in doREDFault. enterREDState(tc); - } - else if(TL == MaxTL) - { + } else if(TL == MaxTL) { + panic("Should go to error state here.. crap\n"); //Do error_state somehow? //Probably inject a WDR fault using the interrupt mechanism. //What should the PC and NPC be set to? - } - else if(TL > MaxPTL && level == Privileged) - { + } else if(TL > MaxPTL && level == Privileged) { //guest_watchdog fault doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, 2); - } - else if(level == Hyperprivileged) - { + } else if(level == Hyperprivileged || + level == Privileged && trapType() >= 384) { doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, trapType()); - } - else - { + } else { doNormalFault(tc, trapType(), false); getPrivVector(tc, PC, NPC, trapType(), TL+1); } diff --git a/src/arch/sparc/interrupts.hh b/src/arch/sparc/interrupts.hh index 70838d1ce..452164e46 100644 --- a/src/arch/sparc/interrupts.hh +++ b/src/arch/sparc/interrupts.hh @@ -32,51 +32,62 @@ #define __ARCH_SPARC_INTERRUPT_HH__ #include "arch/sparc/faults.hh" +#include "cpu/thread_context.hh" + namespace SparcISA { class Interrupts { protected: - Fault interrupts[NumInterruptLevels]; - bool requested[NumInterruptLevels]; + public: Interrupts() { - for(int x = 0; x < NumInterruptLevels; x++) - { - interrupts[x] = new InterruptLevelN(x); - requested[x] = false; - } + } void post(int int_num, int index) { - if(int_num < 0 || int_num >= NumInterruptLevels) - panic("int_num out of bounds\n"); - requested[int_num] = true; } void clear(int int_num, int index) { - requested[int_num] = false; + } void clear_all() { - for(int x = 0; x < NumInterruptLevels; x++) - requested[x] = false; + } bool check_interrupts(ThreadContext * tc) const { - return true; + // so far only handle softint interrupts + int int_level = InterruptLevel(tc->readMiscReg(MISCREG_SOFTINT)); + if (int_level) + return true; + else + return false; } Fault getInterrupt(ThreadContext * tc) { - return NoFault; + // conditioning the softint interrups + if (tc->readMiscReg(MISCREG_HPSTATE) & hpriv) { + // if running in privileged mode, then pend the interrupt + return NoFault; + } else { + int int_level = InterruptLevel(tc->readMiscReg(MISCREG_SOFTINT)); + if ((int_level <= tc->readMiscReg(MISCREG_PIL)) || + !(tc->readMiscReg(MISCREG_PSTATE) & ie)) { + // if PIL or no interrupt enabled, then pend the interrupt + return NoFault; + } else { + return new InterruptLevelN(int_level); + } + } } void updateIntrInfo(ThreadContext * tc) diff --git a/src/arch/sparc/intregfile.hh b/src/arch/sparc/intregfile.hh index 503f3c453..716d45a65 100644 --- a/src/arch/sparc/intregfile.hh +++ b/src/arch/sparc/intregfile.hh @@ -72,7 +72,7 @@ namespace SparcISA (unsigned int)(-1) : (1 << FrameOffsetBits) - 1; - IntReg regGlobals[MaxGL][RegsPerFrame]; + IntReg regGlobals[MaxGL+1][RegsPerFrame]; IntReg regSegments[2 * NWindows][RegsPerFrame]; IntReg microRegs[NumMicroIntRegs]; IntReg regs[NumIntRegs]; diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index c3cff42ee..5c69598d5 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -529,7 +529,7 @@ decode OP default Unknown::unknown() 0x00: NoPriv::wry({{Y = Rs1 ^ Rs2_or_imm13;}}); //0x01 should cause an illegal instruction exception 0x02: NoPriv::wrccr({{Ccr = Rs1 ^ Rs2_or_imm13;}}); - 0x03: NoPriv::wrasi({{Ccr = Rs1 ^ Rs2_or_imm13;}}); + 0x03: NoPriv::wrasi({{Asi = Rs1 ^ Rs2_or_imm13;}}); //0x04-0x05 should cause an illegal instruction exception 0x06: NoPriv::wrfprs({{Fprs = Rs1 ^ Rs2_or_imm13;}}); //0x07-0x0E should cause an illegal instruction exception @@ -983,6 +983,7 @@ decode OP default Unknown::unknown() Asi = Tstate<31:24>; Ccr = Tstate<39:32>; Gl = Tstate<42:40>; + Hpstate = Htstate; NPC = Tnpc; NNPC = Tnpc + 4; Tl = Tl - 1; @@ -995,6 +996,7 @@ decode OP default Unknown::unknown() Asi = Tstate<31:24>; Ccr = Tstate<39:32>; Gl = Tstate<42:40>; + Hpstate = Htstate; NPC = Tpc; NNPC = Tnpc; Tl = Tl - 1; @@ -1033,36 +1035,36 @@ decode OP default Unknown::unknown() {{uReg0 = Rd.uw; Rd.uw = Mem.uw;}}, {{Mem.uw = uReg0;}}); - format Load { - 0x10: lduwa({{Rd = Mem.uw;}}); - 0x11: lduba({{Rd = Mem.ub;}}); - 0x12: lduha({{Rd = Mem.uhw;}}); + format LoadAlt { + 0x10: lduwa({{Rd = Mem.uw;}}, {{EXT_ASI}}); + 0x11: lduba({{Rd = Mem.ub;}}, {{EXT_ASI}}); + 0x12: lduha({{Rd = Mem.uhw;}}, {{EXT_ASI}}); 0x13: ldda({{ uint64_t val = Mem.udw; RdLow = val<31:0>; RdHigh = val<63:32>; - }}); + }}, {{EXT_ASI}}); } - format Store { - 0x14: stwa({{Mem.uw = Rd;}}); - 0x15: stba({{Mem.ub = Rd;}}); - 0x16: stha({{Mem.uhw = Rd;}}); - 0x17: stda({{Mem.udw = RdLow<31:0> | RdHigh<31:0> << 32;}}); + format StoreAlt { + 0x14: stwa({{Mem.uw = Rd;}}, {{EXT_ASI}}); + 0x15: stba({{Mem.ub = Rd;}}, {{EXT_ASI}}); + 0x16: stha({{Mem.uhw = Rd;}}, {{EXT_ASI}}); + 0x17: stda({{Mem.udw = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{EXT_ASI}}); } - format Load { - 0x18: ldswa({{Rd = (int32_t)Mem.sw;}}); - 0x19: ldsba({{Rd = (int8_t)Mem.sb;}}); - 0x1A: ldsha({{Rd = (int16_t)Mem.shw;}}); - 0x1B: ldxa({{Rd = (int64_t)Mem.sdw;}}); + format LoadAlt { + 0x18: ldswa({{Rd = (int32_t)Mem.sw;}}, {{EXT_ASI}}); + 0x19: ldsba({{Rd = (int8_t)Mem.sb;}}, {{EXT_ASI}}); + 0x1A: ldsha({{Rd = (int16_t)Mem.shw;}}, {{EXT_ASI}}); + 0x1B: ldxa({{Rd = (int64_t)Mem.sdw;}}, {{EXT_ASI}}); } - 0x1D: LoadStore::ldstuba( + 0x1D: LoadStoreAlt::ldstuba( {{Rd = Mem.ub;}}, - {{Mem.ub = 0xFF}}); - 0x1E: Store::stxa({{Mem.udw = Rd}}); - 0x1F: LoadStore::swapa( + {{Mem.ub = 0xFF}}, {{EXT_ASI}}); + 0x1E: StoreAlt::stxa({{Mem.udw = Rd}}, {{EXT_ASI}}); + 0x1F: LoadStoreAlt::swapa( {{uReg0 = Rd.uw; Rd.uw = Mem.uw;}}, - {{Mem.uw = uReg0;}}); + {{Mem.uw = uReg0;}}, {{EXT_ASI}}); format Trap { 0x20: Load::ldf({{Frd.uw = Mem.uw;}}); 0x21: decode X { @@ -1079,7 +1081,7 @@ decode OP default Unknown::unknown() 0x26: stqf({{fault = new FpDisabled;}}); 0x27: Store::stdf({{Mem.udw = Frd.udw;}}); 0x2D: Nop::prefetch({{ }}); - 0x30: Load::ldfa({{Frd.uw = Mem.uw;}}); + 0x30: LoadAlt::ldfa({{Frd.uw = Mem.uw;}}, {{EXT_ASI}}); 0x32: ldqfa({{fault = new FpDisabled;}}); format LoadAlt { 0x33: decode EXT_ASI { @@ -1131,7 +1133,7 @@ decode OP default Unknown::unknown() //ASI_BLOCK_AS_IF_USER_SECONDARY_LITTLE 0x1F: FailUnimpl::ldblockf_aiusl(); //ASI_BLOCK_PRIMARY - 0xF0: ldblockf_p({{Frd_N.udw = Mem.udw;}}); + 0xF0: ldblockf_p({{Frd_N.udw = Mem.udw;}}, {{EXT_ASI}}); //ASI_BLOCK_SECONDARY 0xF1: FailUnimpl::ldblockf_s(); //ASI_BLOCK_PRIMARY_LITTLE @@ -1214,7 +1216,7 @@ decode OP default Unknown::unknown() //ASI_BLOCK_AS_IF_USER_SECONDARY_LITTLE 0x1F: FailUnimpl::stblockf_aiusl(); //ASI_BLOCK_PRIMARY - 0xF0: stblockf_p({{Mem.udw = Frd_N.udw;}}); + 0xF0: stblockf_p({{Mem.udw = Frd_N.udw;}}, {{EXT_ASI}}); //ASI_BLOCK_SECONDARY 0xF1: FailUnimpl::stblockf_s(); //ASI_BLOCK_PRIMARY_LITTLE @@ -1251,7 +1253,7 @@ decode OP default Unknown::unknown() Mem.uw = Rd.uw; else storeCond = false; - Rd.uw = uReg0;}}); + Rd.uw = uReg0;}}, {{EXT_ASI}}); 0x3D: Nop::prefetcha({{ }}); 0x3E: Cas::casxa( {{uReg0 = Mem.udw;}}, @@ -1259,7 +1261,7 @@ decode OP default Unknown::unknown() Mem.udw = Rd; else storeCond = false; - Rd = uReg0;}}); + Rd = uReg0;}}, {{EXT_ASI}}); } } } diff --git a/src/arch/sparc/isa/formats/mem/basicmem.isa b/src/arch/sparc/isa/formats/mem/basicmem.isa index d5b17d720..ed0c41e61 100644 --- a/src/arch/sparc/isa/formats/mem/basicmem.isa +++ b/src/arch/sparc/isa/formats/mem/basicmem.isa @@ -52,7 +52,7 @@ def template MemDeclare {{ }}; let {{ - def doMemFormat(code, execute, faultCode, name, Name, opt_flags): + def doMemFormat(code, execute, faultCode, name, Name, asi, opt_flags): addrCalcReg = 'EA = Rs1 + Rs2;' addrCalcImm = 'EA = Rs1 + imm;' iop = InstObjParams(name, Name, 'Mem', @@ -72,20 +72,20 @@ let {{ return (header_output, decoder_output, exec_output, decode_block) }}; -def format LoadAlt(code, *opt_flags) {{ +def format LoadAlt(code, asi, *opt_flags) {{ (header_output, decoder_output, exec_output, decode_block) = doMemFormat(code, LoadFuncs, - AlternateAsiPrivFaultCheck, name, Name, opt_flags) + AlternateASIPrivFaultCheck, name, Name, asi, opt_flags) }}; -def format StoreAlt(code, *opt_flags) {{ +def format StoreAlt(code, asi, *opt_flags) {{ (header_output, decoder_output, exec_output, decode_block) = doMemFormat(code, StoreFuncs, - AlternateAsiPrivFaultCheck, name, Name, opt_flags) + AlternateASIPrivFaultCheck, name, Name, asi, opt_flags) }}; def format Load(code, *opt_flags) {{ @@ -93,7 +93,7 @@ def format Load(code, *opt_flags) {{ decoder_output, exec_output, decode_block) = doMemFormat(code, - LoadFuncs, '', name, Name, opt_flags) + LoadFuncs, '', name, Name, 0, opt_flags) }}; def format Store(code, *opt_flags) {{ @@ -101,5 +101,5 @@ def format Store(code, *opt_flags) {{ decoder_output, exec_output, decode_block) = doMemFormat(code, - StoreFuncs, '', name, Name, opt_flags) + StoreFuncs, '', name, Name, 0, opt_flags) }}; diff --git a/src/arch/sparc/isa/formats/mem/blockmem.isa b/src/arch/sparc/isa/formats/mem/blockmem.isa index c124dc600..a0b235a61 100644 --- a/src/arch/sparc/isa/formats/mem/blockmem.isa +++ b/src/arch/sparc/isa/formats/mem/blockmem.isa @@ -273,7 +273,7 @@ def template BlockMemMicroConstructor {{ let {{ - def doBlockMemFormat(code, faultCode, execute, name, Name, opt_flags): + def doBlockMemFormat(code, faultCode, execute, name, Name, asi, opt_flags): # XXX Need to take care of pstate.hpriv as well. The lower ASIs # are split into ones that are available in priv and hpriv, and # those that are only available in hpriv @@ -309,31 +309,31 @@ let {{ makeMicroName(name + "Imm", microPc), makeMicroName(Name, microPc), makeMicroName(Name + "Imm", microPc), - opt_flags); + asi, opt_flags); faultCode = '' return (header_output, decoder_output, exec_output, decode_block) }}; -def format BlockLoad(code, *opt_flags) {{ - # We need to make sure to check the highest priority fault last. - # That way, if other faults have been detected, they'll be overwritten - # rather than the other way around. - faultCode = AlternateASIPrivFaultCheck + BlockAlignmentFaultCheck - (header_output, - decoder_output, - exec_output, - decode_block) = doBlockMemFormat(code, faultCode, - LoadFuncs, name, Name, opt_flags) +def format BlockLoad(code, asi, *opt_flags) {{ + # We need to make sure to check the highest priority fault last. + # That way, if other faults have been detected, they'll be overwritten + # rather than the other way around. + faultCode = AlternateASIPrivFaultCheck + BlockAlignmentFaultCheck + (header_output, + decoder_output, + exec_output, + decode_block) = doBlockMemFormat(code, faultCode, + LoadFuncs, name, Name, asi, opt_flags) }}; -def format BlockStore(code, *opt_flags) {{ - # We need to make sure to check the highest priority fault last. - # That way, if other faults have been detected, they'll be overwritten - # rather than the other way around. - faultCode = AlternateASIPrivFaultCheck + BlockAlignmentFaultCheck - (header_output, - decoder_output, - exec_output, - decode_block) = doBlockMemFormat(code, faultCode, - StoreFuncs, name, Name, opt_flags) +def format BlockStore(code, asi, *opt_flags) {{ + # We need to make sure to check the highest priority fault last. + # That way, if other faults have been detected, they'll be overwritten + # rather than the other way around. + faultCode = AlternateASIPrivFaultCheck + BlockAlignmentFaultCheck + (header_output, + decoder_output, + exec_output, + decode_block) = doBlockMemFormat(code, faultCode, + StoreFuncs, name, Name, asi, opt_flags) }}; diff --git a/src/arch/sparc/isa/formats/mem/util.isa b/src/arch/sparc/isa/formats/mem/util.isa index e87223000..03b08ae18 100644 --- a/src/arch/sparc/isa/formats/mem/util.isa +++ b/src/arch/sparc/isa/formats/mem/util.isa @@ -148,7 +148,7 @@ def template LoadExecute {{ %(fault_check)s; if(fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, 0); + fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, %(asi_val)s); } if(fault == NoFault) { @@ -178,7 +178,7 @@ def template LoadInitiateAcc {{ %(fault_check)s; if(fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, 0); + fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, %(asi_val)s); } return fault; } @@ -222,7 +222,8 @@ def template StoreExecute {{ } if(storeCond && fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, 0); + fault = xc->write((uint%(mem_acc_size)s_t)Mem, + EA, %(asi_val)s, 0); } if(fault == NoFault) { @@ -252,7 +253,8 @@ def template StoreInitiateAcc {{ } if(storeCond && fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, 0); + fault = xc->write((uint%(mem_acc_size)s_t)Mem, + EA, %(asi_val)s, 0); } if(fault == NoFault) { @@ -297,8 +299,9 @@ let {{ # are split into ones that are available in priv and hpriv, and # those that are only available in hpriv AlternateASIPrivFaultCheck = ''' - if(bits(Pstate,2,2) == 0 && (EXT_ASI & 0x80) == 0) - fault = new PrivilegedAction; + if(!bits(Pstate,2,2) && !bits(Hpstate,2,2) && !AsiIsUnPriv((ASI)EXT_ASI) || + !bits(Hpstate,2,2) && AsiIsHPriv((ASI)EXT_ASI)) + fault = new PrivilegedAction; else if(AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2)) fault = new PrivilegedAction; ''' @@ -318,14 +321,15 @@ let {{ //and in the other they're distributed across two. Also note that for //execute functions, the name of the base class doesn't matter. let {{ - def doSplitExecute(execute, name, Name, opt_flags, microParam): + def doSplitExecute(execute, name, Name, asi, opt_flags, microParam): + microParam["asi_val"] = asi; iop = InstObjParams(name, Name, '', microParam, opt_flags) (execf, initf, compf) = execute return execf.subst(iop) + initf.subst(iop) + compf.subst(iop) def doDualSplitExecute(code, eaRegCode, eaImmCode, execute, - faultCode, nameReg, nameImm, NameReg, NameImm, opt_flags): + faultCode, nameReg, nameImm, NameReg, NameImm, asi, opt_flags): executeCode = '' for (eaCode, name, Name) in ( (eaRegCode, nameReg, NameReg), @@ -333,6 +337,6 @@ let {{ microParams = {"code": code, "ea_code": eaCode, "fault_check": faultCode} executeCode += doSplitExecute(execute, name, Name, - opt_flags, microParams) + asi, opt_flags, microParams) return executeCode }}; diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh index 7d786dc3b..2b136856a 100644 --- a/src/arch/sparc/isa_traits.hh +++ b/src/arch/sparc/isa_traits.hh @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black + * Ali Saidi */ #ifndef __ARCH_SPARC_ISA_TRAITS_HH__ @@ -34,19 +35,18 @@ #include "arch/sparc/types.hh" #include "arch/sparc/sparc_traits.hh" #include "config/full_system.hh" +#include "sim/host.hh" class StaticInstPtr; namespace BigEndianGuest {} -#if FULL_SYSTEM -#include "arch/sparc/isa_fullsys_traits.hh" -#endif - namespace SparcISA { class RegFile; + const int MachineBytes = 8; + //This makes sure the big endian versions of certain functions are used. using namespace BigEndianGuest; @@ -94,6 +94,30 @@ namespace SparcISA const int BranchPredAddrShiftAmt = 2; StaticInstPtr decodeInst(ExtMachInst); + +#if FULL_SYSTEM + ////////// Interrupt Stuff /////////// + enum InterruptLevels + { + INTLEVEL_MIN = 1, + INTLEVEL_MAX = 15, + + NumInterruptLevels = INTLEVEL_MAX - INTLEVEL_MIN + }; + + // I don't know what it's for, so I don't + // know what SPARC's value should be + // For loading... XXX This maybe could be USegEnd?? --ali + const Addr LoadAddrMask = ULL(0xffffffffff); + + /////////// TLB Stuff //////////// + const Addr StartVAddrHole = ULL(0x0000800000000000); + const Addr EndVAddrHole = ULL(0xFFFF7FFFFFFFFFFF); + const Addr VAddrAMask = ULL(0xFFFFFFFF); + const Addr PAddrImplMask = ULL(0x000000FFFFFFFFFF); + const Addr BytesInPageMask = ULL(0x1FFF); + +#endif } #endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc index 50a4f4871..6641d38bb 100644 --- a/src/arch/sparc/miscregfile.cc +++ b/src/arch/sparc/miscregfile.cc @@ -37,10 +37,6 @@ #include "cpu/base.hh" #include "cpu/thread_context.hh" -#if FULL_SYSTEM -#include "arch/sparc/system.hh" -#endif - using namespace SparcISA; using namespace std; @@ -51,14 +47,8 @@ string SparcISA::getMiscRegName(RegIndex index) { static::string miscRegName[NumMiscRegs] = {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic", - "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr", - "stick", "stick_cmpr", - "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl", "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin", "wstate",*/ "gl", - "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg", - "hstick_cmpr", - "fsr"}; return miscRegName[index]; } @@ -72,7 +62,7 @@ void MiscRegFile::clear() y = 0; ccr = 0; asi = 0; - tick = 0; + tick = ULL(1) << 63; fprs = 0; gsr = 0; softint = 0; @@ -102,122 +92,276 @@ void MiscRegFile::clear() //This is set this way in Legion for some reason strandStatusReg = 0x50000; fsr = 0; - implicitInstAsi = ASI_PRIMARY; - implicitDataAsi = ASI_PRIMARY; + + priContext = 0; + secContext = 0; + partId = 0; + lsuCtrlReg = 0; + + iTlbC0TsbPs0 = 0; + iTlbC0TsbPs1 = 0; + iTlbC0Config = 0; + iTlbCXTsbPs0 = 0; + iTlbCXTsbPs1 = 0; + iTlbCXConfig = 0; + iTlbSfsr = 0; + iTlbTagAccess = 0; + + dTlbC0TsbPs0 = 0; + dTlbC0TsbPs1 = 0; + dTlbC0Config = 0; + dTlbCXTsbPs0 = 0; + dTlbCXTsbPs1 = 0; + dTlbCXConfig = 0; + dTlbSfsr = 0; + dTlbSfar = 0; + dTlbTagAccess = 0; + + memset(scratchPad, 0, sizeof(scratchPad)); } MiscReg MiscRegFile::readReg(int miscReg) { switch (miscReg) { -// case MISCREG_Y: -// return y; -// case MISCREG_CCR: -// return ccr; - case MISCREG_ASI: - return asi; - case MISCREG_FPRS: - return fprs; - case MISCREG_TICK: - return tick; - case MISCREG_PCR: - panic("PCR not implemented\n"); - case MISCREG_PIC: - panic("PIC not implemented\n"); - case MISCREG_GSR: - return gsr; - case MISCREG_SOFTINT: - return softint; - case MISCREG_TICK_CMPR: - return tick_cmpr; - case MISCREG_STICK: - return stick; - case MISCREG_STICK_CMPR: - return stick_cmpr; + case MISCREG_TLB_DATA: + /* Package up all the data for the tlb: + * 6666555555555544444444443333333333222222222211111111110000000000 + * 3210987654321098765432109876543210987654321098765432109876543210 + * secContext | priContext | |tl|partid| |||||^hpriv + * ||||^red + * |||^priv + * ||^am + * |^lsuim + * ^lsudm + */ + return bits((uint64_t)hpstate,2,2) | + bits((uint64_t)hpstate,5,5) << 1 | + bits((uint64_t)pstate,3,2) << 2 | + bits((uint64_t)lsuCtrlReg,3,2) << 4 | + bits((uint64_t)partId,7,0) << 8 | + bits((uint64_t)tl,2,0) << 16 | + (uint64_t)priContext << 32 | + (uint64_t)secContext << 48; + + case MISCREG_Y: + return y; + case MISCREG_CCR: + return ccr; + case MISCREG_ASI: + return asi; + case MISCREG_FPRS: + return fprs; + case MISCREG_TICK: + return tick; + case MISCREG_PCR: + panic("PCR not implemented\n"); + case MISCREG_PIC: + panic("PIC not implemented\n"); + case MISCREG_GSR: + return gsr; + case MISCREG_SOFTINT: + return softint; + case MISCREG_TICK_CMPR: + return tick_cmpr; + case MISCREG_STICK: + return stick; + case MISCREG_STICK_CMPR: + return stick_cmpr; /** Privilged Registers */ - case MISCREG_TPC: - return tpc[tl-1]; - case MISCREG_TNPC: - return tnpc[tl-1]; - case MISCREG_TSTATE: - return tstate[tl-1]; - case MISCREG_TT: - return tt[tl-1]; - case MISCREG_PRIVTICK: - panic("Priviliged access to tick registers not implemented\n"); - case MISCREG_TBA: - return tba; - case MISCREG_PSTATE: - return pstate; - case MISCREG_TL: - return tl; - case MISCREG_PIL: - return pil; - case MISCREG_CWP: - return cwp; -// case MISCREG_CANSAVE: -// return cansave; -// case MISCREG_CANRESTORE: -// return canrestore; -// case MISCREG_CLEANWIN: -// return cleanwin; -// case MISCREG_OTHERWIN: -// return otherwin; -// case MISCREG_WSTATE: -// return wstate; - case MISCREG_GL: - return gl; + case MISCREG_TPC: + return tpc[tl-1]; + case MISCREG_TNPC: + return tnpc[tl-1]; + case MISCREG_TSTATE: + return tstate[tl-1]; + case MISCREG_TT: + return tt[tl-1]; + case MISCREG_PRIVTICK: + panic("Priviliged access to tick registers not implemented\n"); + case MISCREG_TBA: + return tba; + case MISCREG_PSTATE: + return pstate; + case MISCREG_TL: + return tl; + case MISCREG_PIL: + return pil; + case MISCREG_CWP: + return cwp; + case MISCREG_CANSAVE: + return cansave; + case MISCREG_CANRESTORE: + return canrestore; + case MISCREG_CLEANWIN: + return cleanwin; + case MISCREG_OTHERWIN: + return otherwin; + case MISCREG_WSTATE: + return wstate; + case MISCREG_GL: + return gl; /** Hyper privileged registers */ - case MISCREG_HPSTATE: - return hpstate; - case MISCREG_HTSTATE: - return htstate[tl-1]; - case MISCREG_HINTP: - panic("HINTP not implemented\n"); - case MISCREG_HTBA: - return htba; - case MISCREG_HVER: - return NWindows | MaxTL << 8 | MaxGL << 16; - case MISCREG_STRAND_STS_REG: - return strandStatusReg; - case MISCREG_HSTICK_CMPR: - return hstick_cmpr; + case MISCREG_HPSTATE: + return hpstate; + case MISCREG_HTSTATE: + return htstate[tl-1]; + case MISCREG_HINTP: + panic("HINTP not implemented\n"); + case MISCREG_HTBA: + return htba; + case MISCREG_HVER: + return NWindows | MaxTL << 8 | MaxGL << 16; + case MISCREG_STRAND_STS_REG: + return strandStatusReg; + case MISCREG_HSTICK_CMPR: + return hstick_cmpr; /** Floating Point Status Register */ - case MISCREG_FSR: - return fsr; - default: - panic("Miscellaneous register %d not implemented\n", miscReg); + case MISCREG_FSR: + return fsr; + + case MISCREG_MMU_P_CONTEXT: + return priContext; + case MISCREG_MMU_S_CONTEXT: + return secContext; + case MISCREG_MMU_PART_ID: + return partId; + case MISCREG_MMU_LSU_CTRL: + return lsuCtrlReg; + + case MISCREG_MMU_ITLB_C0_TSB_PS0: + return iTlbC0TsbPs0; + case MISCREG_MMU_ITLB_C0_TSB_PS1: + return iTlbC0TsbPs1; + case MISCREG_MMU_ITLB_C0_CONFIG: + return iTlbC0Config; + case MISCREG_MMU_ITLB_CX_TSB_PS0: + return iTlbCXTsbPs0; + case MISCREG_MMU_ITLB_CX_TSB_PS1: + return iTlbCXTsbPs1; + case MISCREG_MMU_ITLB_CX_CONFIG: + return iTlbCXConfig; + case MISCREG_MMU_ITLB_SFSR: + return iTlbSfsr; + case MISCREG_MMU_ITLB_TAG_ACCESS: + return iTlbTagAccess; + + case MISCREG_MMU_DTLB_C0_TSB_PS0: + return dTlbC0TsbPs0; + case MISCREG_MMU_DTLB_C0_TSB_PS1: + return dTlbC0TsbPs1; + case MISCREG_MMU_DTLB_C0_CONFIG: + return dTlbC0Config; + case MISCREG_MMU_DTLB_CX_TSB_PS0: + return dTlbCXTsbPs0; + case MISCREG_MMU_DTLB_CX_TSB_PS1: + return dTlbCXTsbPs1; + case MISCREG_MMU_DTLB_CX_CONFIG: + return dTlbCXConfig; + case MISCREG_MMU_DTLB_SFSR: + return dTlbSfsr; + case MISCREG_MMU_DTLB_SFAR: + return dTlbSfar; + case MISCREG_MMU_DTLB_TAG_ACCESS: + return dTlbTagAccess; + + case MISCREG_SCRATCHPAD_R0: + return scratchPad[0]; + case MISCREG_SCRATCHPAD_R1: + return scratchPad[1]; + case MISCREG_SCRATCHPAD_R2: + return scratchPad[2]; + case MISCREG_SCRATCHPAD_R3: + return scratchPad[3]; + case MISCREG_SCRATCHPAD_R4: + return scratchPad[4]; + case MISCREG_SCRATCHPAD_R5: + return scratchPad[5]; + case MISCREG_SCRATCHPAD_R6: + return scratchPad[6]; + case MISCREG_SCRATCHPAD_R7: + return scratchPad[7]; + case MISCREG_QUEUE_CPU_MONDO_HEAD: + return cpu_mondo_head; + case MISCREG_QUEUE_CPU_MONDO_TAIL: + return cpu_mondo_tail; + case MISCREG_QUEUE_DEV_MONDO_HEAD: + return dev_mondo_head; + case MISCREG_QUEUE_DEV_MONDO_TAIL: + return dev_mondo_tail; + case MISCREG_QUEUE_RES_ERROR_HEAD: + return res_error_head; + case MISCREG_QUEUE_RES_ERROR_TAIL: + return res_error_tail; + case MISCREG_QUEUE_NRES_ERROR_HEAD: + return nres_error_head; + case MISCREG_QUEUE_NRES_ERROR_TAIL: + return nres_error_tail; + default: + panic("Miscellaneous register %d not implemented\n", miscReg); } } MiscReg MiscRegFile::readRegWithEffect(int miscReg, ThreadContext * tc) { switch (miscReg) { - case MISCREG_TICK: - case MISCREG_PRIVTICK: - return tc->getCpuPtr()->curCycle() - (tick & mask(63)) | - (tick & ~(mask(63))) << 63; - case MISCREG_FPRS: - panic("FPU not implemented\n"); - case MISCREG_PCR: - case MISCREG_PIC: - panic("Performance Instrumentation not impl\n"); + // tick and stick are aliased to each other in niagra + // well store the tick data in stick and the interrupt bit in tick + case MISCREG_STICK: + case MISCREG_TICK: + case MISCREG_PRIVTICK: + // I'm not sure why legion ignores the lowest two bits, but we'll go + // with it + // change from curCycle() to instCount() until we're done with legion + DPRINTFN("Instruction Count when TICK read: %#X stick=%#X\n", + tc->getCpuPtr()->instCount(), stick); + return mbits(tc->getCpuPtr()->instCount() + (int32_t)stick,62,2) | + mbits(tick,63,63); + case MISCREG_FPRS: + warn("FPRS register read and FPU stuff not really implemented\n"); + return fprs; + case MISCREG_PCR: + case MISCREG_PIC: + panic("Performance Instrumentation not impl\n"); /** Floating Point Status Register */ - case MISCREG_FSR: - panic("Floating Point not implemented\n"); -//We'll include this only in FS so we don't need the SparcSystem type around -//in SE. + case MISCREG_FSR: + warn("Reading FSR Floating Point not implemented\n"); + break; + case MISCREG_SOFTINT_CLR: + case MISCREG_SOFTINT_SET: + panic("Can read from softint clr/set\n"); + case MISCREG_SOFTINT: + case MISCREG_TICK_CMPR: + case MISCREG_STICK_CMPR: + case MISCREG_HINTP: + case MISCREG_HTSTATE: + case MISCREG_HTBA: + case MISCREG_HVER: + case MISCREG_STRAND_STS_REG: + case MISCREG_HSTICK_CMPR: + case MISCREG_QUEUE_CPU_MONDO_HEAD: + case MISCREG_QUEUE_CPU_MONDO_TAIL: + case MISCREG_QUEUE_DEV_MONDO_HEAD: + case MISCREG_QUEUE_DEV_MONDO_TAIL: + case MISCREG_QUEUE_RES_ERROR_HEAD: + case MISCREG_QUEUE_RES_ERROR_TAIL: + case MISCREG_QUEUE_NRES_ERROR_HEAD: + case MISCREG_QUEUE_NRES_ERROR_TAIL: #if FULL_SYSTEM - case MISCREG_STICK: - SparcSystem *sys; - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63))); + case MISCREG_HPSTATE: + return readFSRegWithEffect(miscReg, tc); +#else + case MISCREG_HPSTATE: + //HPSTATE is special because because sometimes in privilege checks for instructions + //it will read HPSTATE to make sure the priv. level is ok + //So, we'll just have to tell it it isn't, instead of panicing. + return 0; + + panic("Accessing Fullsystem register %s in SE mode\n",getMiscRegName(miscReg)); #endif - case MISCREG_HVER: - return NWindows | MaxTL << 8 | MaxGL << 16; + } return readReg(miscReg); } @@ -225,239 +369,294 @@ MiscReg MiscRegFile::readRegWithEffect(int miscReg, ThreadContext * tc) void MiscRegFile::setReg(int miscReg, const MiscReg &val) { switch (miscReg) { -// case MISCREG_Y: -// y = val; -// break; -// case MISCREG_CCR: -// ccr = val; -// break; - case MISCREG_ASI: - asi = val; - break; - case MISCREG_FPRS: - fprs = val; - break; - case MISCREG_TICK: - tick = val; - break; - case MISCREG_PCR: - panic("PCR not implemented\n"); - case MISCREG_PIC: - panic("PIC not implemented\n"); - case MISCREG_GSR: - gsr = val; - break; - case MISCREG_SOFTINT: - softint = val; - break; - case MISCREG_TICK_CMPR: - tick_cmpr = val; - break; - case MISCREG_STICK: - stick = val; - break; - case MISCREG_STICK_CMPR: - stick_cmpr = val; - break; + case MISCREG_Y: + y = val; + break; + case MISCREG_CCR: + ccr = val; + break; + case MISCREG_ASI: + asi = val; + break; + case MISCREG_FPRS: + warn("FPU not really implemented writing %#X to FPRS\n", val); + fprs = val; + break; + case MISCREG_TICK: + tick = val; + break; + case MISCREG_PCR: + panic("PCR not implemented\n"); + case MISCREG_PIC: + panic("PIC not implemented\n"); + case MISCREG_GSR: + gsr = val; + break; + case MISCREG_SOFTINT: + softint |= val; + break; + case MISCREG_TICK_CMPR: + tick_cmpr = val; + break; + case MISCREG_STICK: + stick = val; + break; + case MISCREG_STICK_CMPR: + stick_cmpr = val; + break; /** Privilged Registers */ - case MISCREG_TPC: - tpc[tl-1] = val; - break; - case MISCREG_TNPC: - tnpc[tl-1] = val; - break; - case MISCREG_TSTATE: - tstate[tl-1] = val; - break; - case MISCREG_TT: - tt[tl-1] = val; - break; - case MISCREG_PRIVTICK: - panic("Priviliged access to tick regesiters not implemented\n"); - case MISCREG_TBA: - // clear lower 7 bits on writes. - tba = val & ULL(~0x7FFF); - break; - case MISCREG_PSTATE: - pstate = (val & PSTATE_MASK); - break; - case MISCREG_TL: - tl = val; - break; - case MISCREG_PIL: - pil = val; - break; - case MISCREG_CWP: - cwp = val; - break; -// case MISCREG_CANSAVE: -// cansave = val; -// break; -// case MISCREG_CANRESTORE: -// canrestore = val; -// break; -// case MISCREG_CLEANWIN: -// cleanwin = val; -// break; -// case MISCREG_OTHERWIN: -// otherwin = val; -// break; -// case MISCREG_WSTATE: -// wstate = val; -// break; - case MISCREG_GL: - gl = val; - break; + case MISCREG_TPC: + tpc[tl-1] = val; + break; + case MISCREG_TNPC: + tnpc[tl-1] = val; + break; + case MISCREG_TSTATE: + tstate[tl-1] = val; + break; + case MISCREG_TT: + tt[tl-1] = val; + break; + case MISCREG_PRIVTICK: + panic("Priviliged access to tick regesiters not implemented\n"); + case MISCREG_TBA: + // clear lower 7 bits on writes. + tba = val & ULL(~0x7FFF); + break; + case MISCREG_PSTATE: + pstate = (val & PSTATE_MASK); + break; + case MISCREG_TL: + tl = val; + break; + case MISCREG_PIL: + pil = val; + break; + case MISCREG_CWP: + cwp = val; + break; + case MISCREG_CANSAVE: + cansave = val; + break; + case MISCREG_CANRESTORE: + canrestore = val; + break; + case MISCREG_CLEANWIN: + cleanwin = val; + break; + case MISCREG_OTHERWIN: + otherwin = val; + break; + case MISCREG_WSTATE: + wstate = val; + break; + case MISCREG_GL: + gl = val; + break; /** Hyper privileged registers */ - case MISCREG_HPSTATE: - hpstate = val; - break; - case MISCREG_HTSTATE: - htstate[tl-1] = val; - break; - case MISCREG_HINTP: - panic("HINTP not implemented\n"); - case MISCREG_HTBA: - htba = val; - break; - case MISCREG_STRAND_STS_REG: - strandStatusReg = val; - break; - case MISCREG_HSTICK_CMPR: - hstick_cmpr = val; - break; + case MISCREG_HPSTATE: + hpstate = val; + break; + case MISCREG_HTSTATE: + htstate[tl-1] = val; + break; + case MISCREG_HINTP: + panic("HINTP not implemented\n"); + case MISCREG_HTBA: + htba = val; + break; + case MISCREG_STRAND_STS_REG: + strandStatusReg = val; + break; + case MISCREG_HSTICK_CMPR: + hstick_cmpr = val; + break; /** Floating Point Status Register */ - case MISCREG_FSR: - fsr = val; - break; - default: - panic("Miscellaneous register %d not implemented\n", miscReg); - } -} + case MISCREG_FSR: + fsr = val; + break; -inline void MiscRegFile::setImplicitAsis() -{ - //The spec seems to use trap level to indicate the privilege level of the - //processor. It's unclear whether the implicit ASIs should directly depend - //on the trap level, or if they should really be based on the privelege - //bits - if(tl == 0) - { - implicitInstAsi = implicitDataAsi = - (pstate & (1 << 9)) ? ASI_PRIMARY_LITTLE : ASI_PRIMARY; - } - else if(tl <= MaxPTL) - { - implicitInstAsi = ASI_NUCLEUS; - implicitDataAsi = (pstate & (1 << 9)) ? ASI_NUCLEUS_LITTLE : ASI_NUCLEUS; - } - else - { - //This is supposed to force physical addresses to match the spec. - //It might not because of context values and partition values. - implicitInstAsi = implicitDataAsi = ASI_REAL; + case MISCREG_MMU_P_CONTEXT: + priContext = val; + break; + case MISCREG_MMU_S_CONTEXT: + secContext = val; + break; + case MISCREG_MMU_PART_ID: + partId = val; + break; + case MISCREG_MMU_LSU_CTRL: + lsuCtrlReg = val; + break; + + case MISCREG_MMU_ITLB_C0_TSB_PS0: + iTlbC0TsbPs0 = val; + break; + case MISCREG_MMU_ITLB_C0_TSB_PS1: + iTlbC0TsbPs1 = val; + break; + case MISCREG_MMU_ITLB_C0_CONFIG: + iTlbC0Config = val; + break; + case MISCREG_MMU_ITLB_CX_TSB_PS0: + iTlbCXTsbPs0 = val; + break; + case MISCREG_MMU_ITLB_CX_TSB_PS1: + iTlbCXTsbPs1 = val; + break; + case MISCREG_MMU_ITLB_CX_CONFIG: + iTlbCXConfig = val; + break; + case MISCREG_MMU_ITLB_SFSR: + iTlbSfsr = val; + break; + case MISCREG_MMU_ITLB_TAG_ACCESS: + iTlbTagAccess = val; + break; + + case MISCREG_MMU_DTLB_C0_TSB_PS0: + dTlbC0TsbPs0 = val; + break; + case MISCREG_MMU_DTLB_C0_TSB_PS1: + dTlbC0TsbPs1 = val; + break; + case MISCREG_MMU_DTLB_C0_CONFIG: + dTlbC0Config = val; + break; + case MISCREG_MMU_DTLB_CX_TSB_PS0: + dTlbCXTsbPs0 = val; + break; + case MISCREG_MMU_DTLB_CX_TSB_PS1: + dTlbCXTsbPs1 = val; + break; + case MISCREG_MMU_DTLB_CX_CONFIG: + dTlbCXConfig = val; + break; + case MISCREG_MMU_DTLB_SFSR: + dTlbSfsr = val; + break; + case MISCREG_MMU_DTLB_SFAR: + dTlbSfar = val; + break; + case MISCREG_MMU_DTLB_TAG_ACCESS: + dTlbTagAccess = val; + break; + + case MISCREG_SCRATCHPAD_R0: + scratchPad[0] = val; + break; + case MISCREG_SCRATCHPAD_R1: + scratchPad[1] = val; + break; + case MISCREG_SCRATCHPAD_R2: + scratchPad[2] = val; + break; + case MISCREG_SCRATCHPAD_R3: + scratchPad[3] = val; + break; + case MISCREG_SCRATCHPAD_R4: + scratchPad[4] = val; + break; + case MISCREG_SCRATCHPAD_R5: + scratchPad[5] = val; + break; + case MISCREG_SCRATCHPAD_R6: + scratchPad[6] = val; + break; + case MISCREG_SCRATCHPAD_R7: + scratchPad[7] = val; + break; + case MISCREG_QUEUE_CPU_MONDO_HEAD: + cpu_mondo_head = val; + break; + case MISCREG_QUEUE_CPU_MONDO_TAIL: + cpu_mondo_tail = val; + break; + case MISCREG_QUEUE_DEV_MONDO_HEAD: + dev_mondo_head = val; + break; + case MISCREG_QUEUE_DEV_MONDO_TAIL: + dev_mondo_tail = val; + break; + case MISCREG_QUEUE_RES_ERROR_HEAD: + res_error_head = val; + break; + case MISCREG_QUEUE_RES_ERROR_TAIL: + res_error_tail = val; + break; + case MISCREG_QUEUE_NRES_ERROR_HEAD: + nres_error_head = val; + break; + case MISCREG_QUEUE_NRES_ERROR_TAIL: + nres_error_tail = val; + break; + + default: + panic("Miscellaneous register %d not implemented\n", miscReg); } } void MiscRegFile::setRegWithEffect(int miscReg, const MiscReg &val, ThreadContext * tc) { - const uint64_t Bit64 = (1ULL << 63); -#if FULL_SYSTEM - uint64_t time; - SparcSystem *sys; -#endif switch (miscReg) { - case MISCREG_TICK: - tick = tc->getCpuPtr()->curCycle() - val & ~Bit64; - tick |= val & Bit64; - break; - case MISCREG_FPRS: - //Configure the fpu based on the fprs - break; - case MISCREG_PCR: - //Set up performance counting based on pcr value - break; - case MISCREG_PSTATE: - pstate = val & PSTATE_MASK; - setImplicitAsis(); - return; - case MISCREG_TL: - tl = val; - setImplicitAsis(); - return; - case MISCREG_CWP: - tc->changeRegFileContext(CONTEXT_CWP, val); - break; - case MISCREG_GL: - tc->changeRegFileContext(CONTEXT_GLOBALS, val); - break; - case MISCREG_SOFTINT: - //We need to inject interrupts, and or notify the interrupt - //object that it needs to use a different interrupt level. - //Any newly appropriate interrupts will happen when the cpu gets - //around to checking for them. This might not be quite what we - //want. - break; - case MISCREG_SOFTINT_CLR: - //Do whatever this is supposed to do... - break; - case MISCREG_SOFTINT_SET: - //Do whatever this is supposed to do... - break; + case MISCREG_STICK: + case MISCREG_TICK: + // stick and tick are same thing on niagra + // use stick for offset and tick for holding intrrupt bit + stick = mbits(val,62,0) - tc->getCpuPtr()->instCount(); + tick = mbits(val,63,63); + DPRINTFN("Writing TICK=%#X\n", val); + break; + case MISCREG_FPRS: + //Configure the fpu based on the fprs + break; + case MISCREG_PCR: + //Set up performance counting based on pcr value + break; + case MISCREG_PSTATE: + pstate = val & PSTATE_MASK; + return; + case MISCREG_TL: + tl = val; + return; + case MISCREG_CWP: + tc->changeRegFileContext(CONTEXT_CWP, val); + break; + case MISCREG_GL: + tc->changeRegFileContext(CONTEXT_GLOBALS, val); + break; + case MISCREG_PIL: + case MISCREG_SOFTINT: + case MISCREG_TICK_CMPR: + case MISCREG_STICK_CMPR: + case MISCREG_HINTP: + case MISCREG_HTSTATE: + case MISCREG_HTBA: + case MISCREG_HVER: + case MISCREG_STRAND_STS_REG: + case MISCREG_HSTICK_CMPR: + case MISCREG_QUEUE_CPU_MONDO_HEAD: + case MISCREG_QUEUE_CPU_MONDO_TAIL: + case MISCREG_QUEUE_DEV_MONDO_HEAD: + case MISCREG_QUEUE_DEV_MONDO_TAIL: + case MISCREG_QUEUE_RES_ERROR_HEAD: + case MISCREG_QUEUE_RES_ERROR_TAIL: + case MISCREG_QUEUE_NRES_ERROR_HEAD: + case MISCREG_QUEUE_NRES_ERROR_TAIL: #if FULL_SYSTEM - case MISCREG_TICK_CMPR: - if (tickCompare == NULL) - tickCompare = new TickCompareEvent(this, tc); - setReg(miscReg, val); - if ((tick_cmpr & mask(63)) && tickCompare->scheduled()) - tickCompare->deschedule(); - time = (tick_cmpr & mask(63)) - (tick & mask(63)); - if (!(tick_cmpr & ~mask(63)) && time > 0) - tickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); - break; -#endif - case MISCREG_PIL: - //We need to inject interrupts, and or notify the interrupt - //object that it needs to use a different interrupt level. - //Any newly appropriate interrupts will happen when the cpu gets - //around to checking for them. This might not be quite what we - //want. - break; -//We'll include this only in FS so we don't need the SparcSystem type around -//in SE. -#if FULL_SYSTEM - case MISCREG_STICK: - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - sys->sysTick = curTick/Clock::Int::ns - val & ~Bit64; - stick |= val & Bit64; - break; - case MISCREG_STICK_CMPR: - if (sTickCompare == NULL) - sTickCompare = new STickCompareEvent(this, tc); - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - if ((stick_cmpr & ~mask(63)) && sTickCompare->scheduled()) - sTickCompare->deschedule(); - time = (stick_cmpr & mask(63)) - sys->sysTick; - if (!(stick_cmpr & ~mask(63)) && time > 0) - sTickCompare->schedule(time * Clock::Int::ns); - break; - case MISCREG_HSTICK_CMPR: - if (hSTickCompare == NULL) - hSTickCompare = new HSTickCompareEvent(this, tc); - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - if ((hstick_cmpr & ~mask(63)) && hSTickCompare->scheduled()) - hSTickCompare->deschedule(); - int64_t time = (hstick_cmpr & mask(63)) - sys->sysTick; - if (!(hstick_cmpr & ~mask(63)) && time > 0) - hSTickCompare->schedule(time * Clock::Int::ns); - break; + case MISCREG_HPSTATE: + setFSRegWithEffect(miscReg, val, tc); + return; +#else + case MISCREG_HPSTATE: + //HPSTATE is special because normal trap processing saves HPSTATE when + //it goes into a trap, and restores it when it returns. + return; + panic("Accessing Fullsystem register %s to %#x in SE mode\n", getMiscRegName(miscReg), val); #endif } setReg(miscReg, val); @@ -490,8 +689,36 @@ void MiscRegFile::serialize(std::ostream & os) SERIALIZE_ARRAY(htstate, MaxTL); SERIALIZE_SCALAR(htba); SERIALIZE_SCALAR(hstick_cmpr); - SERIALIZE_SCALAR((int)implicitInstAsi); - SERIALIZE_SCALAR((int)implicitDataAsi); + SERIALIZE_SCALAR(strandStatusReg); + SERIALIZE_SCALAR(priContext); + SERIALIZE_SCALAR(secContext); + SERIALIZE_SCALAR(partId); + SERIALIZE_SCALAR(lsuCtrlReg); + SERIALIZE_SCALAR(iTlbC0TsbPs0); + SERIALIZE_SCALAR(iTlbC0TsbPs1); + SERIALIZE_SCALAR(iTlbC0Config); + SERIALIZE_SCALAR(iTlbCXTsbPs0); + SERIALIZE_SCALAR(iTlbCXTsbPs1); + SERIALIZE_SCALAR(iTlbCXConfig); + SERIALIZE_SCALAR(iTlbSfsr); + SERIALIZE_SCALAR(iTlbTagAccess); + SERIALIZE_SCALAR(dTlbC0TsbPs0); + SERIALIZE_SCALAR(dTlbC0TsbPs1); + SERIALIZE_SCALAR(dTlbC0Config); + SERIALIZE_SCALAR(dTlbCXTsbPs0); + SERIALIZE_SCALAR(dTlbCXTsbPs1); + SERIALIZE_SCALAR(dTlbSfsr); + SERIALIZE_SCALAR(dTlbSfar); + SERIALIZE_SCALAR(dTlbTagAccess); + SERIALIZE_ARRAY(scratchPad,8); + SERIALIZE_SCALAR(cpu_mondo_head); + SERIALIZE_SCALAR(cpu_mondo_tail); + SERIALIZE_SCALAR(dev_mondo_head); + SERIALIZE_SCALAR(dev_mondo_tail); + SERIALIZE_SCALAR(res_error_head); + SERIALIZE_SCALAR(res_error_tail); + SERIALIZE_SCALAR(nres_error_head); + SERIALIZE_SCALAR(nres_error_tail); } void MiscRegFile::unserialize(Checkpoint * cp, const std::string & section) @@ -521,29 +748,33 @@ void MiscRegFile::unserialize(Checkpoint * cp, const std::string & section) UNSERIALIZE_ARRAY(htstate, MaxTL); UNSERIALIZE_SCALAR(htba); UNSERIALIZE_SCALAR(hstick_cmpr); - int temp; - UNSERIALIZE_SCALAR(temp); - implicitInstAsi = (ASI)temp; - UNSERIALIZE_SCALAR(temp); - implicitDataAsi = (ASI)temp; -} - -#if FULL_SYSTEM -void -MiscRegFile::processTickCompare(ThreadContext *tc) -{ - panic("tick compare not implemented\n"); -} - -void -MiscRegFile::processSTickCompare(ThreadContext *tc) -{ - panic("tick compare not implemented\n"); -} - -void -MiscRegFile::processHSTickCompare(ThreadContext *tc) -{ - panic("tick compare not implemented\n"); -} -#endif + UNSERIALIZE_SCALAR(strandStatusReg); + UNSERIALIZE_SCALAR(priContext); + UNSERIALIZE_SCALAR(secContext); + UNSERIALIZE_SCALAR(partId); + UNSERIALIZE_SCALAR(lsuCtrlReg); + UNSERIALIZE_SCALAR(iTlbC0TsbPs0); + UNSERIALIZE_SCALAR(iTlbC0TsbPs1); + UNSERIALIZE_SCALAR(iTlbC0Config); + UNSERIALIZE_SCALAR(iTlbCXTsbPs0); + UNSERIALIZE_SCALAR(iTlbCXTsbPs1); + UNSERIALIZE_SCALAR(iTlbCXConfig); + UNSERIALIZE_SCALAR(iTlbSfsr); + UNSERIALIZE_SCALAR(iTlbTagAccess); + UNSERIALIZE_SCALAR(dTlbC0TsbPs0); + UNSERIALIZE_SCALAR(dTlbC0TsbPs1); + UNSERIALIZE_SCALAR(dTlbC0Config); + UNSERIALIZE_SCALAR(dTlbCXTsbPs0); + UNSERIALIZE_SCALAR(dTlbCXTsbPs1); + UNSERIALIZE_SCALAR(dTlbSfsr); + UNSERIALIZE_SCALAR(dTlbSfar); + UNSERIALIZE_SCALAR(dTlbTagAccess); + UNSERIALIZE_ARRAY(scratchPad,8); + UNSERIALIZE_SCALAR(cpu_mondo_head); + UNSERIALIZE_SCALAR(cpu_mondo_tail); + UNSERIALIZE_SCALAR(dev_mondo_head); + UNSERIALIZE_SCALAR(dev_mondo_tail); + UNSERIALIZE_SCALAR(res_error_head); + UNSERIALIZE_SCALAR(res_error_tail); + UNSERIALIZE_SCALAR(nres_error_head); + UNSERIALIZE_SCALAR(nres_error_tail);} diff --git a/src/arch/sparc/miscregfile.hh b/src/arch/sparc/miscregfile.hh index cf0405ac4..ace916f5b 100644 --- a/src/arch/sparc/miscregfile.hh +++ b/src/arch/sparc/miscregfile.hh @@ -32,7 +32,6 @@ #ifndef __ARCH_SPARC_MISCREGFILE_HH__ #define __ARCH_SPARC_MISCREGFILE_HH__ -#include "arch/sparc/asi.hh" #include "arch/sparc/faults.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/types.hh" @@ -58,7 +57,7 @@ namespace SparcISA MISCREG_GSR, MISCREG_SOFTINT_SET, MISCREG_SOFTINT_CLR, - MISCREG_SOFTINT, + MISCREG_SOFTINT, /* 10 */ MISCREG_TICK_CMPR, MISCREG_STICK, MISCREG_STICK_CMPR, @@ -70,7 +69,7 @@ namespace SparcISA MISCREG_TT, MISCREG_PRIVTICK, MISCREG_TBA, - MISCREG_PSTATE, + MISCREG_PSTATE, /* 20 */ MISCREG_TL, MISCREG_PIL, MISCREG_CWP, @@ -82,7 +81,7 @@ namespace SparcISA MISCREG_GL, /** Hyper privileged registers */ - MISCREG_HPSTATE, + MISCREG_HPSTATE, /* 30 */ MISCREG_HTSTATE, MISCREG_HINTP, MISCREG_HTBA, @@ -93,9 +92,74 @@ namespace SparcISA /** Floating Point Status Register */ MISCREG_FSR, + /** MMU Internal Registers */ + MISCREG_MMU_P_CONTEXT, + MISCREG_MMU_S_CONTEXT, /* 40 */ + MISCREG_MMU_PART_ID, + MISCREG_MMU_LSU_CTRL, + + MISCREG_MMU_ITLB_C0_TSB_PS0, + MISCREG_MMU_ITLB_C0_TSB_PS1, + MISCREG_MMU_ITLB_C0_CONFIG, + MISCREG_MMU_ITLB_CX_TSB_PS0, + MISCREG_MMU_ITLB_CX_TSB_PS1, + MISCREG_MMU_ITLB_CX_CONFIG, + MISCREG_MMU_ITLB_SFSR, + MISCREG_MMU_ITLB_TAG_ACCESS, /* 50 */ + + MISCREG_MMU_DTLB_C0_TSB_PS0, + MISCREG_MMU_DTLB_C0_TSB_PS1, + MISCREG_MMU_DTLB_C0_CONFIG, + MISCREG_MMU_DTLB_CX_TSB_PS0, + MISCREG_MMU_DTLB_CX_TSB_PS1, + MISCREG_MMU_DTLB_CX_CONFIG, + MISCREG_MMU_DTLB_SFSR, + MISCREG_MMU_DTLB_SFAR, + MISCREG_MMU_DTLB_TAG_ACCESS, + + /** Scratchpad regiscers **/ + MISCREG_SCRATCHPAD_R0, /* 60 */ + MISCREG_SCRATCHPAD_R1, + MISCREG_SCRATCHPAD_R2, + MISCREG_SCRATCHPAD_R3, + MISCREG_SCRATCHPAD_R4, + MISCREG_SCRATCHPAD_R5, + MISCREG_SCRATCHPAD_R6, + MISCREG_SCRATCHPAD_R7, + + /* CPU Queue Registers */ + MISCREG_QUEUE_CPU_MONDO_HEAD, + MISCREG_QUEUE_CPU_MONDO_TAIL, + MISCREG_QUEUE_DEV_MONDO_HEAD, /* 70 */ + MISCREG_QUEUE_DEV_MONDO_TAIL, + MISCREG_QUEUE_RES_ERROR_HEAD, + MISCREG_QUEUE_RES_ERROR_TAIL, + MISCREG_QUEUE_NRES_ERROR_HEAD, + MISCREG_QUEUE_NRES_ERROR_TAIL, + + /* All the data for the TLB packed up in one register. */ + MISCREG_TLB_DATA, MISCREG_NUMMISCREGS }; + enum HPStateFields { + id = 0x800, // this impl. dependent (id) field must always be '1' for T1000 + ibe = 0x400, + red = 0x20, + hpriv = 0x4, + tlz = 0x1 + }; + + enum PStateFields { + cle = 0x200, + tle = 0x100, + mm = 0xC0, + pef = 0x10, + am = 0x8, + priv = 0x4, + ie = 0x2 + }; + const int NumMiscArchRegs = MISCREG_NUMMISCREGS; const int NumMiscRegs = MISCREG_NUMMISCREGS; @@ -150,12 +214,49 @@ namespace SparcISA /** Floating point misc registers. */ uint64_t fsr; // Floating-Point State Register - ASI implicitInstAsi; - ASI implicitDataAsi; + /** MMU Internal Registers */ + uint16_t priContext; + uint16_t secContext; + uint16_t partId; + uint64_t lsuCtrlReg; + + uint64_t iTlbC0TsbPs0; + uint64_t iTlbC0TsbPs1; + uint64_t iTlbC0Config; + uint64_t iTlbCXTsbPs0; + uint64_t iTlbCXTsbPs1; + uint64_t iTlbCXConfig; + uint64_t iTlbSfsr; + uint64_t iTlbTagAccess; + + uint64_t dTlbC0TsbPs0; + uint64_t dTlbC0TsbPs1; + uint64_t dTlbC0Config; + uint64_t dTlbCXTsbPs0; + uint64_t dTlbCXTsbPs1; + uint64_t dTlbCXConfig; + uint64_t dTlbSfsr; + uint64_t dTlbSfar; + uint64_t dTlbTagAccess; + + uint64_t scratchPad[8]; + + uint64_t cpu_mondo_head; + uint64_t cpu_mondo_tail; + uint64_t dev_mondo_head; + uint64_t dev_mondo_tail; + uint64_t res_error_head; + uint64_t res_error_tail; + uint64_t nres_error_head; + uint64_t nres_error_tail; // These need to check the int_dis field and if 0 then // set appropriate bit in softint and checkinterrutps on the cpu #if FULL_SYSTEM + void setFSRegWithEffect(int miscReg, const MiscReg &val, + ThreadContext *tc); + MiscReg readFSRegWithEffect(int miscReg, ThreadContext * tc); + /** Process a tick compare event and generate an interrupt on the cpu if * appropriate. */ void processTickCompare(ThreadContext *tc); @@ -192,14 +293,14 @@ namespace SparcISA void setRegWithEffect(int miscReg, const MiscReg &val, ThreadContext * tc); - ASI getInstAsid() + int getInstAsid() { - return implicitInstAsi; + return priContext | (uint32_t)partId << 13; } - ASI getDataAsid() + int getDataAsid() { - return implicitDataAsi; + return priContext | (uint32_t)partId << 13; } void serialize(std::ostream & os); @@ -213,7 +314,6 @@ namespace SparcISA bool isHyperPriv() { return (hpstate & (1 << 2)); } bool isPriv() { return (hpstate & (1 << 2)) || (pstate & (1 << 2)); } bool isNonPriv() { return !isPriv(); } - inline void setImplicitAsis(); }; } diff --git a/src/arch/sparc/mmaped_ipr.hh b/src/arch/sparc/mmaped_ipr.hh new file mode 100644 index 000000000..b11c16754 --- /dev/null +++ b/src/arch/sparc/mmaped_ipr.hh @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __ARCH_SPARC_MMAPED_IPR_HH__ +#define __ARCH_SPARC_MMAPED_IPR_HH__ + +/** + * @file + * + * ISA-specific helper functions for memory mapped IPR accesses. + */ + +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "mem/packet.hh" +#include "arch/sparc/tlb.hh" + + +namespace SparcISA +{ +inline Tick +handleIprRead(ThreadContext *xc, Packet *pkt) +{ +#if FULL_SYSTEM + return xc->getDTBPtr()->doMmuRegRead(xc, pkt); +#else + panic("Shouldn't have a memory mapped register in SE\n"); +#endif +} + + +inline Tick +handleIprWrite(ThreadContext *xc, Packet *pkt) +{ +#if FULL_SYSTEM + return xc->getDTBPtr()->doMmuRegWrite(xc, pkt); +#else + panic("Shouldn't have a memory mapped register in SE\n"); +#endif +} + + +} // namespace SparcISA + +#endif diff --git a/src/arch/sparc/pagetable.cc b/src/arch/sparc/pagetable.cc new file mode 100644 index 000000000..22130d41c --- /dev/null +++ b/src/arch/sparc/pagetable.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#include "arch/sparc/pagetable.hh" +#include "sim/serialize.hh" + +namespace SparcISA +{ +void +TlbEntry::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(range.va); + SERIALIZE_SCALAR(range.size); + SERIALIZE_SCALAR(range.contextId); + SERIALIZE_SCALAR(range.partitionId); + SERIALIZE_SCALAR(range.real); + uint64_t entry4u = pte(); + SERIALIZE_SCALAR(entry4u); + SERIALIZE_SCALAR(used); +} + + +void +TlbEntry::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(range.va); + UNSERIALIZE_SCALAR(range.size); + UNSERIALIZE_SCALAR(range.contextId); + UNSERIALIZE_SCALAR(range.partitionId); + UNSERIALIZE_SCALAR(range.real); + uint64_t entry4u; + UNSERIALIZE_SCALAR(entry4u); + pte.populate(entry4u); + UNSERIALIZE_SCALAR(used); +} + + +int PageTableEntry::pageSizes[] = {8*1024, 64*1024, 0, 4*1024*1024, 0, + 256*1024*1024L}; + + +} diff --git a/src/arch/sparc/pagetable.hh b/src/arch/sparc/pagetable.hh new file mode 100644 index 000000000..fc01e82da --- /dev/null +++ b/src/arch/sparc/pagetable.hh @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __ARCH_SPARC_PAGETABLE_HH__ +#define __ARCH_SPARC_PAGETABLE_HH__ + +#include "arch/sparc/isa_traits.hh" +#include "base/bitfield.hh" +#include "base/misc.hh" +#include "config/full_system.hh" + +class Checkpoint; + +namespace SparcISA +{ +struct VAddr +{ + VAddr(Addr a) { panic("not implemented yet."); } +}; + +class PageTableEntry +{ + public: + enum EntryType { + sun4v, + sun4u, + invalid + }; + + private: + uint64_t entry; + EntryType type; + uint64_t entry4u; + bool populated; + + + public: + PageTableEntry() : entry(0), type(invalid), populated(false) {} + + PageTableEntry(uint64_t e, EntryType t = sun4u) + : entry(e), type(t), populated(true) + + { + populate(entry, type); + } + + void populate(uint64_t e, EntryType t = sun4u) + { + entry = e; + type = t; + populated = true; + + // If we get a sun4v format TTE, turn it into a sun4u + if (type == sun4u) + entry4u = entry; + else { + entry4u = 0; + entry4u |= mbits(entry,63,63); //valid + entry4u |= bits(entry,1,0) << 61; //size[1:0] + entry4u |= bits(entry,62,62) << 60; //nfo + entry4u |= bits(entry,12,12) << 59; //ie + entry4u |= bits(entry,2,2) << 48; //size[2] + entry4u |= mbits(entry,39,13); //paddr + entry4u |= bits(entry,61,61) << 6;; // locked + entry4u |= bits(entry,10,10) << 5; //cp + entry4u |= bits(entry,9,9) << 4; //cv + entry4u |= bits(entry,11,11) << 3; //e + entry4u |= bits(entry,8,8) << 2; //p + entry4u |= bits(entry,6,6) << 1; //w + } + } + + void clear() + { + populated = false; + } + + static int pageSizes[6]; + + + uint64_t operator()() const { assert(populated); return entry4u; } + const PageTableEntry &operator=(uint64_t e) { populated = true; + entry4u = e; return *this; } + + const PageTableEntry &operator=(const PageTableEntry &e) + { populated = true; entry4u = e.entry4u; return *this; } + + bool valid() const { return bits(entry4u,63,63) && populated; } + uint8_t _size() const { assert(populated); + return bits(entry4u, 62,61) | + bits(entry4u, 48,48) << 2; } + Addr size() const { assert(_size() < 6); return pageSizes[_size()]; } + bool ie() const { return bits(entry4u, 59,59); } + Addr pfn() const { assert(populated); return bits(entry4u,39,13); } + Addr paddr() const { assert(populated); return mbits(entry4u, 39,13);} + bool locked() const { assert(populated); return bits(entry4u,6,6); } + bool cv() const { assert(populated); return bits(entry4u,4,4); } + bool cp() const { assert(populated); return bits(entry4u,5,5); } + bool priv() const { assert(populated); return bits(entry4u,2,2); } + bool writable() const { assert(populated); return bits(entry4u,1,1); } + bool nofault() const { assert(populated); return bits(entry4u,60,60); } + bool sideffect() const { assert(populated); return bits(entry4u,3,3); } +}; + +struct TlbRange { + Addr va; + Addr size; + int contextId; + int partitionId; + bool real; + + inline bool operator<(const TlbRange &r2) const + { + if (real && !r2.real) + return true; + if (!real && r2.real) + return false; + + if (!real && !r2.real) { + if (contextId < r2.contextId) + return true; + else if (contextId > r2.contextId) + return false; + } + + if (partitionId < r2.partitionId) + return true; + else if (partitionId > r2.partitionId) + return false; + + if (va < r2.va) + return true; + return false; + } + inline bool operator==(const TlbRange &r2) const + { + return va == r2.va && + size == r2.size && + contextId == r2.contextId && + partitionId == r2.partitionId && + real == r2.real; + } +}; + + +struct TlbEntry { + TlbRange range; + PageTableEntry pte; + bool used; + bool valid; + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + +}; + + +}; // namespace SparcISA + +#endif // __ARCH_SPARC_PAGE_TABLE_HH__ + diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc index 29aca50c6..691d0a0f1 100644 --- a/src/arch/sparc/regfile.cc +++ b/src/arch/sparc/regfile.cc @@ -320,6 +320,92 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) // FSR dest->setMiscReg(MISCREG_FSR, src->readMiscReg(MISCREG_FSR)); + + //Strand Status Register + dest->setMiscReg(MISCREG_STRAND_STS_REG, + src->readMiscReg(MISCREG_STRAND_STS_REG)); + + // MMU Registers + dest->setMiscReg(MISCREG_MMU_P_CONTEXT, + src->readMiscReg(MISCREG_MMU_P_CONTEXT)); + dest->setMiscReg(MISCREG_MMU_S_CONTEXT, + src->readMiscReg(MISCREG_MMU_S_CONTEXT)); + dest->setMiscReg(MISCREG_MMU_PART_ID, + src->readMiscReg(MISCREG_MMU_PART_ID)); + dest->setMiscReg(MISCREG_MMU_LSU_CTRL, + src->readMiscReg(MISCREG_MMU_LSU_CTRL)); + + dest->setMiscReg(MISCREG_MMU_ITLB_C0_TSB_PS0, + src->readMiscReg(MISCREG_MMU_ITLB_C0_TSB_PS0)); + dest->setMiscReg(MISCREG_MMU_ITLB_C0_TSB_PS1, + src->readMiscReg(MISCREG_MMU_ITLB_C0_TSB_PS1)); + dest->setMiscReg(MISCREG_MMU_ITLB_C0_CONFIG, + src->readMiscReg(MISCREG_MMU_ITLB_C0_CONFIG)); + dest->setMiscReg(MISCREG_MMU_ITLB_CX_TSB_PS0, + src->readMiscReg(MISCREG_MMU_ITLB_CX_TSB_PS0)); + dest->setMiscReg(MISCREG_MMU_ITLB_CX_TSB_PS1, + src->readMiscReg(MISCREG_MMU_ITLB_CX_TSB_PS1)); + dest->setMiscReg(MISCREG_MMU_ITLB_CX_CONFIG, + src->readMiscReg(MISCREG_MMU_ITLB_CX_CONFIG)); + dest->setMiscReg(MISCREG_MMU_ITLB_SFSR, + src->readMiscReg(MISCREG_MMU_ITLB_SFSR)); + dest->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS, + src->readMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS)); + + dest->setMiscReg(MISCREG_MMU_DTLB_C0_TSB_PS0, + src->readMiscReg(MISCREG_MMU_DTLB_C0_TSB_PS0)); + dest->setMiscReg(MISCREG_MMU_DTLB_C0_TSB_PS1, + src->readMiscReg(MISCREG_MMU_DTLB_C0_TSB_PS1)); + dest->setMiscReg(MISCREG_MMU_DTLB_C0_CONFIG, + src->readMiscReg(MISCREG_MMU_DTLB_C0_CONFIG)); + dest->setMiscReg(MISCREG_MMU_DTLB_CX_TSB_PS0, + src->readMiscReg(MISCREG_MMU_DTLB_CX_TSB_PS0)); + dest->setMiscReg(MISCREG_MMU_DTLB_CX_TSB_PS1, + src->readMiscReg(MISCREG_MMU_DTLB_CX_TSB_PS1)); + dest->setMiscReg(MISCREG_MMU_DTLB_CX_CONFIG, + src->readMiscReg(MISCREG_MMU_DTLB_CX_CONFIG)); + dest->setMiscReg(MISCREG_MMU_DTLB_SFSR, + src->readMiscReg(MISCREG_MMU_DTLB_SFSR)); + dest->setMiscReg(MISCREG_MMU_DTLB_SFAR, + src->readMiscReg(MISCREG_MMU_DTLB_SFAR)); + dest->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS, + src->readMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS)); + + // Scratchpad Registers + dest->setMiscReg(MISCREG_SCRATCHPAD_R0, + src->readMiscReg(MISCREG_SCRATCHPAD_R0)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R1, + src->readMiscReg(MISCREG_SCRATCHPAD_R1)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R2, + src->readMiscReg(MISCREG_SCRATCHPAD_R2)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R3, + src->readMiscReg(MISCREG_SCRATCHPAD_R3)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R4, + src->readMiscReg(MISCREG_SCRATCHPAD_R4)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R5, + src->readMiscReg(MISCREG_SCRATCHPAD_R5)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R6, + src->readMiscReg(MISCREG_SCRATCHPAD_R6)); + dest->setMiscReg(MISCREG_SCRATCHPAD_R7, + src->readMiscReg(MISCREG_SCRATCHPAD_R7)); + + // Queue Registers + dest->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD, + src->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD)); + dest->setMiscReg(MISCREG_QUEUE_CPU_MONDO_TAIL, + src->readMiscReg(MISCREG_QUEUE_CPU_MONDO_TAIL)); + dest->setMiscReg(MISCREG_QUEUE_DEV_MONDO_HEAD, + src->readMiscReg(MISCREG_QUEUE_DEV_MONDO_HEAD)); + dest->setMiscReg(MISCREG_QUEUE_DEV_MONDO_TAIL, + src->readMiscReg(MISCREG_QUEUE_DEV_MONDO_TAIL)); + dest->setMiscReg(MISCREG_QUEUE_RES_ERROR_HEAD, + src->readMiscReg(MISCREG_QUEUE_RES_ERROR_HEAD)); + dest->setMiscReg(MISCREG_QUEUE_RES_ERROR_TAIL, + src->readMiscReg(MISCREG_QUEUE_RES_ERROR_TAIL)); + dest->setMiscReg(MISCREG_QUEUE_NRES_ERROR_HEAD, + src->readMiscReg(MISCREG_QUEUE_NRES_ERROR_HEAD)); + dest->setMiscReg(MISCREG_QUEUE_NRES_ERROR_TAIL, + src->readMiscReg(MISCREG_QUEUE_NRES_ERROR_TAIL)); } void SparcISA::copyRegs(ThreadContext *src, ThreadContext *dest) diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh index 51f1b5fef..d9af0757c 100644 --- a/src/arch/sparc/regfile.hh +++ b/src/arch/sparc/regfile.hh @@ -82,12 +82,12 @@ namespace SparcISA void setMiscRegWithEffect(int miscReg, const MiscReg &val, ThreadContext * tc); - ASI instAsid() + int instAsid() { return miscRegFile.getInstAsid(); } - ASI dataAsid() + int dataAsid() { return miscRegFile.getDataAsid(); } diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc index 72c87f0ad..da83d86fc 100644 --- a/src/arch/sparc/system.cc +++ b/src/arch/sparc/system.cc @@ -155,6 +155,11 @@ SparcSystem::SparcSystem(Params *p) if (!hypervisor->loadLocalSymbols(debugSymbolTable)) panic("could not load hypervisor symbols\n"); + // Strip off the rom address so when the hypervisor is copied into memory we + // have symbols still + if (!hypervisor->loadLocalSymbols(debugSymbolTable, 0xFFFFFF)) + panic("could not load hypervisor symbols\n"); + if (!nvram->loadGlobalSymbols(debugSymbolTable)) panic("could not load reset symbols\n"); diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc index 0b1a2ff5f..675287d18 100644 --- a/src/arch/sparc/tlb.cc +++ b/src/arch/sparc/tlb.cc @@ -25,55 +25,1054 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Nathan Binkert - * Steve Reinhardt - * Andrew Schultz + * Authors: Ali Saidi */ +#include "arch/sparc/asi.hh" +#include "arch/sparc/miscregfile.hh" #include "arch/sparc/tlb.hh" +#include "base/bitfield.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "mem/packet_access.hh" +#include "mem/request.hh" #include "sim/builder.hh" +/* @todo remove some of the magic constants. -- ali + * */ namespace SparcISA { - DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB) - BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB) +TLB::TLB(const std::string &name, int s) + : SimObject(name), size(s), usedEntries(0), cacheValid(false) +{ + // To make this work you'll have to change the hypervisor and OS + if (size > 64) + fatal("SPARC T1 TLB registers don't support more than 64 TLB entries."); + + tlb = new TlbEntry[size]; + memset(tlb, 0, sizeof(TlbEntry) * size); +} + +void +TLB::clearUsedBits() +{ + MapIter i; + for (i = lookupTable.begin(); i != lookupTable.end();) { + TlbEntry *t = i->second; + if (!t->pte.locked()) { + t->used = false; + usedEntries--; + } + } +} + + +void +TLB::insert(Addr va, int partition_id, int context_id, bool real, + const PageTableEntry& PTE, int entry) +{ + + + MapIter i; + TlbEntry *new_entry = NULL; + int x; + + cacheValid = false; + + DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d\n", + va, PTE.paddr(), partition_id, context_id, (int)real); + + if (entry != -1) { + assert(entry < size && entry >= 0); + new_entry = &tlb[entry]; + } else { + for (x = 0; x < size; x++) { + if (!tlb[x].valid || !tlb[x].used) { + new_entry = &tlb[x]; + break; + } + } + } + + // Update the last ently if their all locked + if (!new_entry) + new_entry = &tlb[size-1]; + + assert(PTE.valid()); + new_entry->range.va = va; + new_entry->range.size = PTE.size(); + new_entry->range.partitionId = partition_id; + new_entry->range.contextId = context_id; + new_entry->range.real = real; + new_entry->pte = PTE; + new_entry->used = true;; + new_entry->valid = true; + usedEntries++; + + + // Demap any entry that conflicts + i = lookupTable.find(new_entry->range); + if (i != lookupTable.end()) { + i->second->valid = false; + if (i->second->used) { + i->second->used = false; + usedEntries--; + } + DPRINTF(TLB, "TLB: Found conflicting entry, deleting it\n"); + lookupTable.erase(i); + } + + lookupTable.insert(new_entry->range, new_entry);; + + // If all entries have there used bit set, clear it on them all, but the + // one we just inserted + if (usedEntries == size) { + clearUsedBits(); + new_entry->used = true; + usedEntries++; + } + +} + + +TlbEntry* +TLB::lookup(Addr va, int partition_id, bool real, int context_id) +{ + MapIter i; + TlbRange tr; + TlbEntry *t; + + DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n", + va, partition_id, context_id, real); + // Assemble full address structure + tr.va = va; + tr.size = va + MachineBytes; + tr.contextId = context_id; + tr.partitionId = partition_id; + tr.real = real; + + // Try to find the entry + i = lookupTable.find(tr); + if (i == lookupTable.end()) { + DPRINTF(TLB, "TLB: No valid entry found\n"); + return NULL; + } + + // Mark the entries used bit and clear other used bits in needed + t = i->second; + DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(), + t->pte.size()); + if (!t->used) { + t->used = true; + usedEntries++; + if (usedEntries == size) { + clearUsedBits(); + t->used = true; + usedEntries++; + } + } + + return t; +} + +void +TLB::dumpAll() +{ + for (int x = 0; x < size; x++) { + if (tlb[x].valid) { + DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n", + x, tlb[x].range.partitionId, tlb[x].range.contextId, + tlb[x].range.real ? 'R' : ' ', tlb[x].range.size, + tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte()); + } + } +} + +void +TLB::demapPage(Addr va, int partition_id, bool real, int context_id) +{ + TlbRange tr; + MapIter i; + + cacheValid = false; + + // Assemble full address structure + tr.va = va; + tr.size = va + MachineBytes; + tr.contextId = context_id; + tr.partitionId = partition_id; + tr.real = real; + + // Demap any entry that conflicts + i = lookupTable.find(tr); + if (i != lookupTable.end()) { + i->second->valid = false; + if (i->second->used) { + i->second->used = false; + usedEntries--; + } + lookupTable.erase(i); + } +} + +void +TLB::demapContext(int partition_id, int context_id) +{ + int x; + cacheValid = false; + for (x = 0; x < size; x++) { + if (tlb[x].range.contextId == context_id && + tlb[x].range.partitionId == partition_id) { + tlb[x].valid = false; + if (tlb[x].used) { + tlb[x].used = false; + usedEntries--; + } + lookupTable.erase(tlb[x].range); + } + } +} + +void +TLB::demapAll(int partition_id) +{ + int x; + cacheValid = false; + for (x = 0; x < size; x++) { + if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) { + tlb[x].valid = false; + if (tlb[x].used) { + tlb[x].used = false; + usedEntries--; + } + lookupTable.erase(tlb[x].range); + } + } +} + +void +TLB::invalidateAll() +{ + int x; + cacheValid = false; + + for (x = 0; x < size; x++) { + tlb[x].valid = false; + } + usedEntries = 0; +} + +uint64_t +TLB::TteRead(int entry) { + assert(entry < size); + return tlb[entry].pte(); +} + +uint64_t +TLB::TagRead(int entry) { + assert(entry < size); + uint64_t tag; + + tag = tlb[entry].range.contextId | tlb[entry].range.va | + (uint64_t)tlb[entry].range.partitionId << 61; + tag |= tlb[entry].range.real ? ULL(1) << 60 : 0; + tag |= (uint64_t)~tlb[entry].pte._size() << 56; + return tag; +} + +bool +TLB::validVirtualAddress(Addr va, bool am) +{ + if (am) + return true; + if (va >= StartVAddrHole && va <= EndVAddrHole) + return false; + return true; +} + +void +TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct, + bool se, FaultTypes ft, int asi) +{ + uint64_t sfsr; + sfsr = tc->readMiscReg(reg); + + if (sfsr & 0x1) + sfsr = 0x3; + else + sfsr = 1; + + if (write) + sfsr |= 1 << 2; + sfsr |= ct << 4; + if (se) + sfsr |= 1 << 6; + sfsr |= ft << 7; + sfsr |= asi << 16; + tc->setMiscRegWithEffect(reg, sfsr); +} + +void +TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context) +{ + tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0)); +} + +void +ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct, + bool se, FaultTypes ft, int asi) +{ + DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n", + (int)write, ct, ft, asi); + TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi); +} + +void +ITB::writeTagAccess(ThreadContext *tc, Addr va, int context) +{ + TLB::writeTagAccess(tc, MISCREG_MMU_ITLB_TAG_ACCESS, va, context); +} + +void +DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct, + bool se, FaultTypes ft, int asi) +{ + DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n", + a, (int)write, ct, ft, asi); + TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR, a); +} + +void +DTB::writeTagAccess(ThreadContext *tc, Addr va, int context) +{ + TLB::writeTagAccess(tc, MISCREG_MMU_DTLB_TAG_ACCESS, va, context); +} + + + +Fault +ITB::translate(RequestPtr &req, ThreadContext *tc) +{ + uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA); + + Addr vaddr = req->getVaddr(); + TlbEntry *e; + + assert(req->getAsi() == ASI_IMPLICIT); + + DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n", + vaddr, req->getSize()); + + // Be fast if we can! + if (cacheValid && cacheState == tlbdata) { + if (cacheEntry) { + if (cacheEntry->range.va < vaddr + sizeof(MachInst) && + cacheEntry->range.va + cacheEntry->range.size >= vaddr) { + req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) | + vaddr & cacheEntry->pte.size()-1 ); + return NoFault; + } + } else { + req->setPaddr(vaddr & PAddrImplMask); + return NoFault; + } + } + + bool hpriv = bits(tlbdata,0,0); + bool red = bits(tlbdata,1,1); + bool priv = bits(tlbdata,2,2); + bool addr_mask = bits(tlbdata,3,3); + bool lsu_im = bits(tlbdata,4,4); + + int part_id = bits(tlbdata,15,8); + int tl = bits(tlbdata,18,16); + int pri_context = bits(tlbdata,47,32); + int context; + ContextType ct; + int asi; + bool real = false; + + DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n", + priv, hpriv, red, lsu_im, part_id); - Param<int> size; + if (tl > 0) { + asi = ASI_N; + ct = Nucleus; + context = 0; + } else { + asi = ASI_P; + ct = Primary; + context = pri_context; + } + + if ( hpriv || red ) { + cacheValid = true; + cacheState = tlbdata; + cacheEntry = NULL; + req->setPaddr(vaddr & PAddrImplMask); + return NoFault; + } + + // If the access is unaligned trap + if (vaddr & 0x3) { + writeSfsr(tc, false, ct, false, OtherFault, asi); + return new MemAddressNotAligned; + } + + if (addr_mask) + vaddr = vaddr & VAddrAMask; + + if (!validVirtualAddress(vaddr, addr_mask)) { + writeSfsr(tc, false, ct, false, VaOutOfRange, asi); + return new InstructionAccessException; + } + + if (!lsu_im) { + e = lookup(vaddr, part_id, true); + real = true; + context = 0; + } else { + e = lookup(vaddr, part_id, false, context); + } + + if (e == NULL || !e->valid) { + tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS, + vaddr & ~BytesInPageMask | context); + if (real) + return new InstructionRealTranslationMiss; + else + return new FastInstructionAccessMMUMiss; + } + + // were not priviledged accesing priv page + if (!priv && e->pte.priv()) { + writeSfsr(tc, false, ct, false, PrivViolation, asi); + return new InstructionAccessException; + } + + // cache translation date for next translation + cacheValid = true; + cacheState = tlbdata; + cacheEntry = e; + + req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | + vaddr & e->pte.size()-1 ); + DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); + return NoFault; +} + + + +Fault +DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +{ + /* @todo this could really use some profiling and fixing to make it faster! */ + uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA); + Addr vaddr = req->getVaddr(); + Addr size = req->getSize(); + ASI asi; + asi = (ASI)req->getAsi(); + bool implicit = false; + bool hpriv = bits(tlbdata,0,0); + + DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n", + vaddr, size, asi); + + if (asi == ASI_IMPLICIT) + implicit = true; + + if (hpriv && implicit) { + req->setPaddr(vaddr & PAddrImplMask); + return NoFault; + } + + // Be fast if we can! + if (cacheValid && cacheState == tlbdata) { + if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size && + cacheEntry[0]->range.va + cacheEntry[0]->range.size >= vaddr) { + req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) | + vaddr & cacheEntry[0]->pte.size()-1 ); + return NoFault; + } + if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size && + cacheEntry[1]->range.va + cacheEntry[1]->range.size >= vaddr) { + req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) | + vaddr & cacheEntry[1]->pte.size()-1 ); + return NoFault; + } + } + + bool red = bits(tlbdata,1,1); + bool priv = bits(tlbdata,2,2); + bool addr_mask = bits(tlbdata,3,3); + bool lsu_dm = bits(tlbdata,5,5); + + int part_id = bits(tlbdata,15,8); + int tl = bits(tlbdata,18,16); + int pri_context = bits(tlbdata,47,32); + int sec_context = bits(tlbdata,47,32); + + bool real = false; + ContextType ct = Primary; + int context = 0; + + TlbEntry *e; + + DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n", + priv, hpriv, red, lsu_dm, part_id); + + if (implicit) { + if (tl > 0) { + asi = ASI_N; + ct = Nucleus; + context = 0; + } else { + asi = ASI_P; + ct = Primary; + context = pri_context; + } + } else if (!hpriv && !red) { + if (tl > 0 || AsiIsNucleus(asi)) { + ct = Nucleus; + context = 0; + } else if (AsiIsSecondary(asi)) { + ct = Secondary; + context = sec_context; + } else { + context = pri_context; + ct = Primary; //??? + } + + // We need to check for priv level/asi priv + if (!priv && !AsiIsUnPriv(asi)) { + // It appears that context should be Nucleus in these cases? + writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi); + return new PrivilegedAction; + } + if (priv && AsiIsHPriv(asi)) { + writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi); + return new DataAccessException; + } + + } else if (hpriv) { + if (asi == ASI_P) { + ct = Primary; + context = pri_context; + goto continueDtbFlow; + } + } + + if (!implicit) { + if (AsiIsLittle(asi)) + panic("Little Endian ASIs not supported\n"); + if (AsiIsBlock(asi)) + panic("Block ASIs not supported\n"); + if (AsiIsNoFault(asi)) + panic("No Fault ASIs not supported\n"); + if (write && asi == ASI_LDTX_P) + // block init store (like write hint64) + goto continueDtbFlow; + if (AsiIsTwin(asi)) + panic("Twin ASIs not supported\n"); + if (AsiIsPartialStore(asi)) + panic("Partial Store ASIs not supported\n"); + if (AsiIsInterrupt(asi)) + panic("Interrupt ASIs not supported\n"); + + if (AsiIsMmu(asi)) + goto handleMmuRegAccess; + if (AsiIsScratchPad(asi)) + goto handleScratchRegAccess; + if (AsiIsQueue(asi)) + goto handleQueueRegAccess; + if (AsiIsSparcError(asi)) + goto handleSparcErrorRegAccess; + + if (!AsiIsReal(asi) && !AsiIsNucleus(asi)) + panic("Accessing ASI %#X. Should we?\n", asi); + } + +continueDtbFlow: + // If the asi is unaligned trap + if (vaddr & size-1) { + writeSfr(tc, vaddr, false, ct, false, OtherFault, asi); + return new MemAddressNotAligned; + } + + if (addr_mask) + vaddr = vaddr & VAddrAMask; + + if (!validVirtualAddress(vaddr, addr_mask)) { + writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi); + return new DataAccessException; + } + + + if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) { + real = true; + context = 0; + }; + + if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) { + req->setPaddr(vaddr & PAddrImplMask); + return NoFault; + } + + e = lookup(vaddr, part_id, real, context); - END_DECLARE_SIM_OBJECT_PARAMS(ITB) + if (e == NULL || !e->valid) { + tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS, + vaddr & ~BytesInPageMask | context); + DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n"); + if (real) + return new DataRealTranslationMiss; + else + return new FastDataAccessMMUMiss; + + } - BEGIN_INIT_SIM_OBJECT_PARAMS(ITB) - INIT_PARAM_DFLT(size, "TLB size", 48) + if (write && !e->pte.writable()) { + writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi); + return new FastDataAccessProtection; + } - END_INIT_SIM_OBJECT_PARAMS(ITB) + if (e->pte.nofault() && !AsiIsNoFault(asi)) { + writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi); + return new DataAccessException; + } + if (e->pte.sideffect()) + req->setFlags(req->getFlags() | UNCACHEABLE); - CREATE_SIM_OBJECT(ITB) - { - return new ITB(getInstanceName(), size); + + if (!priv && e->pte.priv()) { + writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi); + return new DataAccessException; } - REGISTER_SIM_OBJECT("SparcITB", ITB) + // cache translation date for next translation + cacheValid = true; + cacheState = tlbdata; + if (cacheEntry[0] != e && cacheEntry[1] != e) { + cacheEntry[1] = cacheEntry[0]; + cacheEntry[0] = e; + cacheAsi[1] = cacheAsi[0]; + cacheAsi[0] = asi; + if (implicit) + cacheAsi[0] = (ASI)0; + } - BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB) + req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | + vaddr & e->pte.size()-1); + DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); + return NoFault; + /** Normal flow ends here. */ - Param<int> size; +handleScratchRegAccess: + if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) { + writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + return new DataAccessException; + } + goto regAccessOk; + +handleQueueRegAccess: + if (!priv && !hpriv) { + writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + return new PrivilegedAction; + } + if (priv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) { + writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + return new DataAccessException; + } + goto regAccessOk; + +handleSparcErrorRegAccess: + if (!hpriv) { + if (priv) { + writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + return new DataAccessException; + } else { + writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + return new PrivilegedAction; + } + } + goto regAccessOk; - END_DECLARE_SIM_OBJECT_PARAMS(DTB) - BEGIN_INIT_SIM_OBJECT_PARAMS(DTB) +regAccessOk: +handleMmuRegAccess: + DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n"); + req->setMmapedIpr(true); + req->setPaddr(req->getVaddr()); + return NoFault; +}; - INIT_PARAM_DFLT(size, "TLB size", 64) +Tick +DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) +{ + Addr va = pkt->getAddr(); + ASI asi = (ASI)pkt->req->getAsi(); + uint64_t temp, data; + uint64_t tsbtemp, cnftemp; - END_INIT_SIM_OBJECT_PARAMS(DTB) + DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n", + (uint32_t)pkt->req->getAsi(), pkt->getAddr()); + switch (asi) { + case ASI_LSU_CONTROL_REG: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL)); + break; + case ASI_MMU: + switch (va) { + case 0x8: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT)); + break; + case 0x10: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT)); + break; + default: + goto doMmuReadError; + } + break; + case ASI_QUEUE: + pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD + + (va >> 4) - 0x3c)); + break; + case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0)); + break; + case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1)); + break; + case ASI_DMMU_CTXT_ZERO_CONFIG: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG)); + break; + case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0)); + break; + case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1)); + break; + case ASI_IMMU_CTXT_ZERO_CONFIG: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG)); + break; + case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0)); + break; + case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1)); + break; + case ASI_DMMU_CTXT_NONZERO_CONFIG: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG)); + break; + case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0)); + break; + case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1)); + break; + case ASI_IMMU_CTXT_NONZERO_CONFIG: + assert(va == 0); + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG)); + break; + case ASI_SPARC_ERROR_STATUS_REG: + warn("returning 0 for SPARC ERROR regsiter read\n"); + pkt->set(0); + break; + case ASI_HYP_SCRATCHPAD: + case ASI_SCRATCHPAD: + pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3))); + break; + case ASI_IMMU: + switch (va) { + case 0x0: + temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); + pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); + break; + case 0x30: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS)); + break; + default: + goto doMmuReadError; + } + break; + case ASI_DMMU: + switch (va) { + case 0x0: + temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); + pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); + break; + case 0x30: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS)); + break; + case 0x80: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID)); + break; + default: + goto doMmuReadError; + } + break; + case ASI_DMMU_TSB_PS0_PTR_REG: + temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); + if (bits(temp,12,0) == 0) { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG); + } else { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG); + } + data = mbits(tsbtemp,63,13); + data |= temp >> (9 + bits(cnftemp,2,0) * 3) & + mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); + pkt->set(data); + break; + case ASI_DMMU_TSB_PS1_PTR_REG: + temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); + if (bits(temp,12,0) == 0) { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG); + } else { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG); + } + data = mbits(tsbtemp,63,13); + if (bits(tsbtemp,12,12)) + data |= ULL(1) << (13+bits(tsbtemp,3,0)); + data |= temp >> (9 + bits(cnftemp,2,0) * 3) & + mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); + pkt->set(data); + break; - CREATE_SIM_OBJECT(DTB) - { - return new DTB(getInstanceName(), size); + default: +doMmuReadError: + panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n", + (uint32_t)asi, va); } + pkt->result = Packet::Success; + return tc->getCpuPtr()->cycles(1); +} + +Tick +DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) +{ + uint64_t data = gtoh(pkt->get<uint64_t>()); + Addr va = pkt->getAddr(); + ASI asi = (ASI)pkt->req->getAsi(); + + Addr ta_insert; + Addr va_insert; + Addr ct_insert; + int part_insert; + int entry_insert = -1; + bool real_insert; + PageTableEntry pte; + + DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n", + (uint32_t)asi, va, data); + + switch (asi) { + case ASI_LSU_CONTROL_REG: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data); + break; + case ASI_MMU: + switch (va) { + case 0x8: + tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data); + break; + case 0x10: + tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data); + break; + default: + goto doMmuWriteError; + } + break; + case ASI_QUEUE: + assert(mbits(data,13,6) == data); + tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD + + (va >> 4) - 0x3c, data); + break; + case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data); + break; + case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data); + break; + case ASI_DMMU_CTXT_ZERO_CONFIG: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data); + break; + case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data); + break; + case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data); + break; + case ASI_IMMU_CTXT_ZERO_CONFIG: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data); + break; + case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data); + break; + case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data); + break; + case ASI_DMMU_CTXT_NONZERO_CONFIG: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data); + break; + case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data); + break; + case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data); + break; + case ASI_IMMU_CTXT_NONZERO_CONFIG: + assert(va == 0); + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data); + break; + case ASI_SPARC_ERROR_EN_REG: + case ASI_SPARC_ERROR_STATUS_REG: + warn("Ignoring write to SPARC ERROR regsiter\n"); + break; + case ASI_HYP_SCRATCHPAD: + case ASI_SCRATCHPAD: + tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data); + break; + case ASI_IMMU: + switch (va) { + case 0x30: + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data); + break; + default: + goto doMmuWriteError; + } + break; + case ASI_ITLB_DATA_ACCESS_REG: + entry_insert = bits(va, 8,3); + case ASI_ITLB_DATA_IN_REG: + assert(entry_insert != -1 || mbits(va,10,9) == va); + ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); + va_insert = mbits(ta_insert, 63,13); + ct_insert = mbits(ta_insert, 12,0); + part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID); + real_insert = bits(va, 9,9); + pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : + PageTableEntry::sun4u); + tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert, + pte, entry_insert); + break; + case ASI_DTLB_DATA_ACCESS_REG: + entry_insert = bits(va, 8,3); + case ASI_DTLB_DATA_IN_REG: + assert(entry_insert != -1 || mbits(va,10,9) == va); + ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); + va_insert = mbits(ta_insert, 63,13); + ct_insert = mbits(ta_insert, 12,0); + part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID); + real_insert = bits(va, 9,9); + pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : + PageTableEntry::sun4u); + insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert); + break; + case ASI_DMMU: + switch (va) { + case 0x30: + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data); + break; + case 0x80: + tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data); + break; + default: + goto doMmuWriteError; + } + break; + default: +doMmuWriteError: + panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n", + (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data); + } + pkt->result = Packet::Success; + return tc->getCpuPtr()->cycles(1); +} + +void +TLB::serialize(std::ostream &os) +{ + panic("Need to implement serialize tlb for SPARC\n"); +} + +void +TLB::unserialize(Checkpoint *cp, const std::string §ion) +{ + panic("Need to implement unserialize tlb for SPARC\n"); +} + + +DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB) + + Param<int> size; + +END_DECLARE_SIM_OBJECT_PARAMS(ITB) + +BEGIN_INIT_SIM_OBJECT_PARAMS(ITB) + + INIT_PARAM_DFLT(size, "TLB size", 48) + +END_INIT_SIM_OBJECT_PARAMS(ITB) + + +CREATE_SIM_OBJECT(ITB) +{ + return new ITB(getInstanceName(), size); +} + +REGISTER_SIM_OBJECT("SparcITB", ITB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB) + + Param<int> size; + +END_DECLARE_SIM_OBJECT_PARAMS(DTB) + +BEGIN_INIT_SIM_OBJECT_PARAMS(DTB) + + INIT_PARAM_DFLT(size, "TLB size", 64) + +END_INIT_SIM_OBJECT_PARAMS(DTB) + + +CREATE_SIM_OBJECT(DTB) +{ + return new DTB(getInstanceName(), size); +} - REGISTER_SIM_OBJECT("SparcDTB", DTB) +REGISTER_SIM_OBJECT("SparcDTB", DTB) } diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh index 136103f44..f69b40ffb 100644 --- a/src/arch/sparc/tlb.hh +++ b/src/arch/sparc/tlb.hh @@ -31,57 +31,144 @@ #ifndef __ARCH_SPARC_TLB_HH__ #define __ARCH_SPARC_TLB_HH__ +#include "arch/sparc/asi.hh" +#include "arch/sparc/tlb_map.hh" #include "base/misc.hh" #include "mem/request.hh" #include "sim/faults.hh" #include "sim/sim_object.hh" class ThreadContext; +class Packet; namespace SparcISA { - const int PAddrImplBits = 40; - const Addr PAddrImplMask = (ULL(1) << PAddrImplBits) - 1; - class TLB : public SimObject - { - public: - TLB(const std::string &name, int size) : SimObject(name) - { - } +class TLB : public SimObject +{ + protected: + TlbMap lookupTable;; + typedef TlbMap::iterator MapIter; + + TlbEntry *tlb; + + int size; + int usedEntries; + + uint64_t cacheState; + bool cacheValid; + + enum FaultTypes { + OtherFault = 0, + PrivViolation = 0x1, + SideEffect = 0x2, + AtomicToIo = 0x4, + IllegalAsi = 0x8, + LoadFromNfo = 0x10, + VaOutOfRange = 0x20, + VaOutOfRangeJmp = 0x40 }; - class ITB : public TLB - { - public: - ITB(const std::string &name, int size) : TLB(name, size) - { - } - - Fault translate(RequestPtr &req, ThreadContext *tc) const - { - //For now, always assume the address is already physical. - //Also assume that there are 40 bits of physical address space. - req->setPaddr(req->getVaddr() & PAddrImplMask); - return NoFault; - } + enum ContextType { + Primary = 0, + Secondary = 1, + Nucleus = 2 }; - class DTB : public TLB + + /** lookup an entry in the TLB based on the partition id, and real bit if + * real is true or the partition id, and context id if real is false. + * @param va the virtual address not shifted (e.g. bottom 13 bits are 0) + * @param paritition_id partition this entry is for + * @param real is this a real->phys or virt->phys translation + * @param context_id if this is virt->phys what context + * @return A pointer to a tlb entry + */ + TlbEntry *lookup(Addr va, int partition_id, bool real, int context_id = 0); + + /** Insert a PTE into the TLB. */ + void insert(Addr vpn, int partition_id, int context_id, bool real, + const PageTableEntry& PTE, int entry = -1); + + /** Given an entry id, read that tlb entries' tag. */ + uint64_t TagRead(int entry); + + /** Give an entry id, read that tlb entries' tte */ + uint64_t TteRead(int entry); + + /** Remove all entries from the TLB */ + void invalidateAll(); + + /** Remove all non-locked entries from the tlb that match partition id. */ + void demapAll(int partition_id); + + /** Remove all entries that match a given context/partition id. */ + void demapContext(int partition_id, int context_id); + + /** Remve all entries that match a certain partition id, (contextid), and + * va). */ + void demapPage(Addr va, int partition_id, bool real, int context_id); + + /** Checks if the virtual address provided is a valid one. */ + bool validVirtualAddress(Addr va, bool am); + + void writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct, + bool se, FaultTypes ft, int asi); + + void TLB::clearUsedBits(); + + + void writeTagAccess(ThreadContext *tc, int reg, Addr va, int context); + + public: + TLB(const std::string &name, int size); + + void dumpAll(); + + // Checkpointing + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +class ITB : public TLB +{ + public: + ITB(const std::string &name, int size) : TLB(name, size) { - public: - DTB(const std::string &name, int size) : TLB(name, size) - { - } - - Fault translate(RequestPtr &req, ThreadContext *tc, bool write) const - { - //For now, always assume the address is already physical. - //Also assume that there are 40 bits of physical address space. - req->setPaddr(req->getVaddr() & ((1ULL << 40) - 1)); - return NoFault; - } - }; + cacheEntry = NULL; + } + + Fault translate(RequestPtr &req, ThreadContext *tc); + private: + void writeSfsr(ThreadContext *tc, bool write, ContextType ct, + bool se, FaultTypes ft, int asi); + void writeTagAccess(ThreadContext *tc, Addr va, int context); + TlbEntry *cacheEntry; + friend class DTB; +}; + +class DTB : public TLB +{ + public: + DTB(const std::string &name, int size) : TLB(name, size) + { + cacheEntry[0] = NULL; + cacheEntry[1] = NULL; + } + + Fault translate(RequestPtr &req, ThreadContext *tc, bool write); + Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); + Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); + + private: + void writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct, + bool se, FaultTypes ft, int asi); + void writeTagAccess(ThreadContext *tc, Addr va, int context); + + TlbEntry *cacheEntry[2]; + ASI cacheAsi[2]; +}; + } #endif // __ARCH_SPARC_TLB_HH__ diff --git a/src/arch/sparc/tlb_map.hh b/src/arch/sparc/tlb_map.hh new file mode 100644 index 000000000..688daf5b9 --- /dev/null +++ b/src/arch/sparc/tlb_map.hh @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __ARCH_SPARC_TLB_MAP_HH__ +#define __ARCH_SPARC_TLB_MAP_HH__ + +#include "arch/sparc/pagetable.hh" +#include <map> + +namespace SparcISA +{ + +class TlbMap +{ + private: + typedef std::map<TlbRange, TlbEntry*> RangeMap; + RangeMap tree; + + public: + typedef RangeMap::iterator iterator; + + iterator find(const TlbRange &r) + { + iterator i; + + i = tree.upper_bound(r); + + if (i == tree.begin()) + if (r.real == i->first.real && + r.partitionId == i->first.partitionId && + i->first.va < r.va + r.size && + i->first.va+i->first.size >= r.va && + (r.real || r.contextId == i->first.contextId)) + return i; + else + // Nothing could match, so return end() + return tree.end(); + + i--; + + if (r.real != i->first.real) + return tree.end(); + if (!r.real && r.contextId != i->first.contextId) + return tree.end(); + if (r.partitionId != i->first.partitionId) + return tree.end(); + if (i->first.va <= r.va+r.size && + i->first.va+i->first.size >= r.va) + return i; + + return tree.end(); + } + + bool intersect(const TlbRange &r) + { + iterator i; + i = find(r); + if (i != tree.end()) + return true; + return false; + } + + + iterator insert(TlbRange &r, TlbEntry *d) + { + if (intersect(r)) + return tree.end(); + + return tree.insert(std::make_pair<TlbRange,TlbEntry*>(r, d)).first; + } + + size_t erase(TlbRange k) + { + return tree.erase(k); + } + + void erase(iterator p) + { + tree.erase(p); + } + + void erase(iterator p, iterator q) + { + tree.erase(p,q); + } + + void clear() + { + tree.erase(tree.begin(), tree.end()); + } + + iterator begin() + { + return tree.begin(); + } + + iterator end() + { + return tree.end(); + } + + size_t size() + { + return tree.size(); + } + + bool empty() + { + return tree.empty(); + } +}; + +}; + +#endif // __ARCH_SPARC_TLB_MAP_HH__ diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc index 6493ddfd5..0db5f6acc 100644 --- a/src/arch/sparc/ua2005.cc +++ b/src/arch/sparc/ua2005.cc @@ -28,27 +28,27 @@ * Authors: Ali Saidi */ -#include "arch/sparc/regfile.hh" +#include "arch/sparc/miscregfile.hh" +#include "base/bitfield.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" -Fault -SparcISA::MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val, +using namespace SparcISA; + +void +MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val, ThreadContext *tc) { int64_t time; - SparcSystem *sys; switch (miscReg) { /* Full system only ASRs */ case MISCREG_SOFTINT: - if (isNonPriv()) - return new PrivilegedOpcode; // Check if we are going to interrupt because of something - int oldLevel = InterruptLevel(softint); - int newLevel = InterruptLevel(val); setReg(miscReg, val); - if (newLevel > oldLevel) - ; // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX - //tc->getCpuPtr()->checkInterrupts = true; - return NoFault; + tc->getCpuPtr()->checkInterrupts = true; + warn("Writing to softint not really supported, writing: %#x\n", val); + break; case MISCREG_SOFTINT_CLR: return setRegWithEffect(miscReg, ~val & softint, tc); @@ -56,152 +56,131 @@ SparcISA::MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val, return setRegWithEffect(miscReg, val | softint, tc); case MISCREG_TICK_CMPR: - if (isNonPriv()) - return new PrivilegedOpcode; if (tickCompare == NULL) tickCompare = new TickCompareEvent(this, tc); setReg(miscReg, val); - if (tick_cmprFields.int_dis && tickCompare.scheduled()) - tickCompare.deschedule(); - time = tick_cmprFields.tick_cmpr - tickFields.counter; - if (!tick_cmprFields.int_dis && time > 0) - tickCompare.schedule(time * tc->getCpuPtr()->cycles(1)); - return NoFault; - - case MISCREG_STICK: - if (isNonPriv()) - return new PrivilegedOpcode; - if (isPriv()) - return new PrivilegedAction; - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - sys->sysTick = curTick/Clock::Int::ns - val & ~Bit64; - stickFields.npt = val & Bit64 ? 1 : 0; - return NoFault; + if ((tick_cmpr & mask(63)) && tickCompare->scheduled()) + tickCompare->deschedule(); + time = (tick_cmpr & mask(63)) - (tick & mask(63)); + if (!(tick_cmpr & ~mask(63)) && time > 0) + tickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); + warn ("writing to TICK compare register %#X\n", val); + break; case MISCREG_STICK_CMPR: - if (isNonPriv()) - return new PrivilegedOpcode; if (sTickCompare == NULL) sTickCompare = new STickCompareEvent(this, tc); - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); setReg(miscReg, val); - if (stick_cmprFields.int_dis && sTickCompare.scheduled()) - sTickCompare.deschedule(); - time = stick_cmprFields.tick_cmpr - sys->sysTick; - if (!stick_cmprFields.int_dis && time > 0) - sTickCompare.schedule(time * Clock::Int::ns); - return NoFault; - - /* Fullsystem only Priv registers. */ - case MISCREG_PIL: - if (FULL_SYSTEM) { - setReg(miscReg, val); - //tc->getCpuPtr()->checkInterrupts; - // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX - return NoFault; - } else - panic("PIL not implemented for syscall emulation\n"); - - /* Hyper privileged registers */ - case MISCREG_HPSTATE: - case MISCREG_HINTP: + if ((stick_cmpr & mask(63)) && sTickCompare->scheduled()) + sTickCompare->deschedule(); + time = (stick_cmpr & mask(63)) - (stick & mask(63)); + if (!(stick_cmpr & ~mask(63)) && time > 0) + sTickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); + warn ("writing to sTICK compare register value %#X\n", val); + break; + + case MISCREG_PSTATE: + if (val & ie && !(pstate & ie)) { + tc->getCpuPtr()->checkInterrupts = true; + } setReg(miscReg, val); - return NoFault; - case MISCREG_HTSTATE: - if (tl == 0) - return new IllegalInstruction; + + case MISCREG_PIL: + if (val < pil) { + tc->getCpuPtr()->checkInterrupts = true; + } setReg(miscReg, val); - return NoFault; + break; + + case MISCREG_HVER: + panic("Shouldn't be writing HVER\n"); case MISCREG_HTBA: // clear lower 7 bits on writes. setReg(miscReg, val & ULL(~0x7FFF)); - return NoFault; + break; + + case MISCREG_QUEUE_CPU_MONDO_HEAD: + case MISCREG_QUEUE_CPU_MONDO_TAIL: + case MISCREG_QUEUE_DEV_MONDO_HEAD: + case MISCREG_QUEUE_DEV_MONDO_TAIL: + case MISCREG_QUEUE_RES_ERROR_HEAD: + case MISCREG_QUEUE_RES_ERROR_TAIL: + case MISCREG_QUEUE_NRES_ERROR_HEAD: + case MISCREG_QUEUE_NRES_ERROR_TAIL: + setReg(miscReg, val); + tc->getCpuPtr()->checkInterrupts = true; + break; - case MISCREG_STRAND_STS_REG: - setReg(miscReg, strandStatusReg); - return NoFault; case MISCREG_HSTICK_CMPR: - if (isNonPriv()) - return new PrivilegedOpcode; if (hSTickCompare == NULL) hSTickCompare = new HSTickCompareEvent(this, tc); - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); setReg(miscReg, val); - if (hstick_cmprFields.int_dis && hSTickCompare.scheduled()) - hSTickCompare.deschedule(); - int64_t time = hstick_cmprFields.tick_cmpr - sys->sysTick; - if (!hstick_cmprFields.int_dis && time > 0) - hSTickCompare.schedule(time * Clock::Int::ns); - return NoFault; + if ((hstick_cmpr & mask(63)) && hSTickCompare->scheduled()) + hSTickCompare->deschedule(); + time = (hstick_cmpr & mask(63)) - (stick & mask(63)); + if (!(hstick_cmpr & ~mask(63)) && time > 0) + hSTickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); + warn ("writing to hsTICK compare register value %#X\n", val); + break; + + case MISCREG_HPSTATE: + // T1000 spec says impl. dependent val must always be 1 + setReg(miscReg, val | id); + break; + case MISCREG_HTSTATE: + case MISCREG_STRAND_STS_REG: + setReg(miscReg, val); + break; + default: - return new IllegalInstruction; + panic("Invalid write to FS misc register %s\n", getMiscRegName(miscReg)); } } MiscReg -MiscRegFile::readFSRegWithEffect(int miscReg, Fault &fault, ThreadContext * tc) +MiscRegFile::readFSRegWithEffect(int miscReg, ThreadContext * tc) { switch (miscReg) { - - /* Privileged registers. */ - case MISCREG_SOFTINT: - if (isNonPriv()) { - fault = new PrivilegedOpcode; - return 0; - } - return readReg(miscReg); - case MISCREG_TICK_CMPR: - if (isNonPriv()) { - fault = new PrivilegedOpcode; - return 0; - } - return readReg(miscReg); + /* Privileged registers. */ + case MISCREG_QUEUE_CPU_MONDO_HEAD: + case MISCREG_QUEUE_CPU_MONDO_TAIL: + case MISCREG_QUEUE_DEV_MONDO_HEAD: + case MISCREG_QUEUE_DEV_MONDO_TAIL: + case MISCREG_QUEUE_RES_ERROR_HEAD: + case MISCREG_QUEUE_RES_ERROR_TAIL: + case MISCREG_QUEUE_NRES_ERROR_HEAD: + case MISCREG_QUEUE_NRES_ERROR_TAIL: + case MISCREG_SOFTINT: + case MISCREG_TICK_CMPR: + case MISCREG_STICK_CMPR: + case MISCREG_PIL: + case MISCREG_HPSTATE: + case MISCREG_HINTP: + case MISCREG_HTSTATE: + case MISCREG_STRAND_STS_REG: + case MISCREG_HSTICK_CMPR: + return readReg(miscReg) ; + + case MISCREG_HTBA: + return readReg(miscReg) & ULL(~0x7FFF); + case MISCREG_HVER: + return NWindows | MaxTL << 8 | MaxGL << 16; + + default: + panic("Invalid read to FS misc register\n"); + } +} +/* + In Niagra STICK==TICK so this isn't needed case MISCREG_STICK: SparcSystem *sys; - if (stickFields.npt && !isNonPriv()) { - fault = new PrivilegedAction; - return 0; - } sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); assert(sys != NULL); - return curTick/Clock::Int::ns - sys->sysTick | stickFields.npt << 63; - case MISCREG_STICK_CMPR: - if (isNonPriv()) { - fault = new PrivilegedOpcode; - return 0; - } - return readReg(miscReg); + return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63))); +*/ - /* Hyper privileged registers */ - case MISCREG_HPSTATE: - case MISCREG_HINTP: - return readReg(miscReg); - case MISCREG_HTSTATE: - if (tl == 0) { - fault = new IllegalInstruction; - return 0; - } - return readReg(miscReg); - - case MISCREG_HTBA: - return readReg(miscReg) & ULL(~0x7FFF); - case MISCREG_HVER: - return NWindows | MaxTL << 8 | MaxGL << 16; - case MISCREG_STRAND_STS_REG: - return strandStatusReg; - case MISCREG_HSTICK_CMPR: - return hstick_cmpr; - - default: - fault = new IllegalInstruction; - return 0; - } -} void MiscRegFile::processTickCompare(ThreadContext *tc) @@ -221,4 +200,3 @@ MiscRegFile::processHSTickCompare(ThreadContext *tc) panic("tick compare not implemented\n"); } -}; // namespace SparcISA diff --git a/src/arch/sparc/vtophys.hh b/src/arch/sparc/vtophys.hh index bf2b757d6..66679a565 100644 --- a/src/arch/sparc/vtophys.hh +++ b/src/arch/sparc/vtophys.hh @@ -33,6 +33,7 @@ #define __ARCH_SPARC_VTOPHYS_H__ #include "arch/sparc/isa_traits.hh" +#include "arch/sparc/pagetable.hh" class ThreadContext; class FunctionalPort; |