diff options
81 files changed, 4439 insertions, 1569 deletions
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 1c0a56362..72742775f 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -89,17 +89,18 @@ def makeSparcSystem(mem_mode, mdesc = None): self.bridge = Bridge() self.t1000 = T1000() self.t1000.attachIO(self.iobus) - self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem()), zero = True) + self.physmem = PhysicalMemory(range = AddrRange(Addr('1MB'), size = '64MB'), zero = True) + self.physmem2 = PhysicalMemory(range = AddrRange(Addr('2GB'), size ='256MB'), zero = True) self.bridge.side_a = self.iobus.port self.bridge.side_b = self.membus.port self.physmem.port = self.membus.port + self.physmem2.port = self.membus.port self.rom.port = self.membus.port self.nvram.port = self.membus.port self.hypervisor_desc.port = self.membus.port self.partition_desc.port = self.membus.port self.intrctrl = IntrControl() self.mem_mode = mem_mode - self.kernel = binary('vmlinux') self.reset_bin = binary('reset.bin') self.hypervisor_bin = binary('q.bin') diff --git a/configs/example/fs.py b/configs/example/fs.py index a70a60b97..d479d717e 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -92,7 +92,13 @@ else: else: bm = [SysConfig()] -test_sys = makeLinuxAlphaSystem(test_mem_mode, bm[0]) +if m5.build_env['TARGET_ISA'] == "alpha": + test_sys = makeLinuxAlphaSystem(test_mem_mode, bm[0]) +elif m5.build_env['TARGET_ISA'] == "sparc": + test_sys = makeSparcSystem(test_mem_mode, bm[0]) +else: + m5.panic("incapable of building non-alpha or non-sparc full system!") + np = options.num_cpus if options.l2cache: @@ -113,7 +119,10 @@ for i in xrange(np): test_sys.cpu[i].connectMemPorts(test_sys.membus) if len(bm) == 2: - drive_sys = makeLinuxAlphaSystem(drive_mem_mode, bm[1]) + if m5.build_env['TARGET_ISA'] == 'alpha': + drive_sys = makeLinuxAlphaSystem(drive_mem_mode, bm[1]) + elif m5.build_env['TARGET_ISA'] == 'sparc': + drive_sys = makeSparcSystem(drive_mem_mode, bm[1]) drive_sys.cpu = DriveCPUClass(cpu_id=0) drive_sys.cpu.connectMemPorts(drive_sys.membus) root = makeDualRoot(test_sys, drive_sys, options.etherdump) 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; diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh index 177279678..1fc0bad5d 100644 --- a/src/base/bitfield.hh +++ b/src/base/bitfield.hh @@ -58,6 +58,18 @@ bits(T val, int first, int last) } /** + * Mask off the given bits in place like bits() but without shifting. + * msb = 63, lsb = 0 + */ +template <class T> +inline +T +mbits(T val, int first, int last) +{ + return val & (mask(first+1) & ~mask(last)); +} + +/** * Sign-extend an N-bit value to 64 bits. */ template <int N> diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc index 6691bd4ae..8fbad8030 100644 --- a/src/base/loader/aout_object.cc +++ b/src/base/loader/aout_object.cc @@ -82,14 +82,14 @@ AoutObject::AoutObject(const string &_filename, int _fd, bool -AoutObject::loadGlobalSymbols(SymbolTable *symtab) +AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) { // a.out symbols not supported yet return false; } bool -AoutObject::loadLocalSymbols(SymbolTable *symtab) +AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) { // a.out symbols not supported yet return false; diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh index d180d69f3..7bac5be65 100644 --- a/src/base/loader/aout_object.hh +++ b/src/base/loader/aout_object.hh @@ -48,8 +48,10 @@ class AoutObject : public ObjectFile public: virtual ~AoutObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); static ObjectFile *tryFile(const std::string &fname, int fd, size_t len, uint8_t *data); diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc index 134f2d98d..a5a0ad9a4 100644 --- a/src/base/loader/ecoff_object.cc +++ b/src/base/loader/ecoff_object.cc @@ -86,7 +86,7 @@ EcoffObject::EcoffObject(const string &_filename, int _fd, bool -EcoffObject::loadGlobalSymbols(SymbolTable *symtab) +EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) { if (!symtab) return false; @@ -115,7 +115,7 @@ EcoffObject::loadGlobalSymbols(SymbolTable *symtab) } bool -EcoffObject::loadLocalSymbols(SymbolTable *symtab) +EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) { if (!symtab) return false; diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh index 05c604b2b..ca6fa2dd0 100644 --- a/src/base/loader/ecoff_object.hh +++ b/src/base/loader/ecoff_object.hh @@ -52,8 +52,10 @@ class EcoffObject : public ObjectFile public: virtual ~EcoffObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); static ObjectFile *tryFile(const std::string &fname, int fd, size_t len, uint8_t *data); diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 2ca0d4f4a..7339507f6 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -330,13 +330,13 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) } bool -ElfObject::loadGlobalSymbols(SymbolTable *symtab) +ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) { return loadSomeSymbols(symtab, STB_GLOBAL); } bool -ElfObject::loadLocalSymbols(SymbolTable *symtab) +ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) { return loadSomeSymbols(symtab, STB_LOCAL); } diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index 9755426b4..fb728b3c5 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -53,8 +53,10 @@ class ElfObject : public ObjectFile public: virtual ~ElfObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); static ObjectFile *tryFile(const std::string &fname, int fd, size_t len, uint8_t *data); diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 64085185d..6e98332c5 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -78,8 +78,10 @@ class ObjectFile virtual bool loadSections(Port *memPort, Addr addrMask = std::numeric_limits<Addr>::max()); - virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0; - virtual bool loadLocalSymbols(SymbolTable *symtab) = 0; + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()) = 0; + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()) = 0; Arch getArch() const { return arch; } OpSys getOpSys() const { return opSys; } diff --git a/src/base/loader/raw_object.cc b/src/base/loader/raw_object.cc index 1faf33426..2a52b0d6e 100644 --- a/src/base/loader/raw_object.cc +++ b/src/base/loader/raw_object.cc @@ -61,21 +61,21 @@ RawObject::RawObject(const std::string &_filename, int _fd, size_t _len, } bool -RawObject::loadGlobalSymbols(SymbolTable *symtab) +RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) { int fnameStart = filename.rfind('/',filename.size()) + 1; int extStart = filename.rfind('.',filename.size()); - symtab->insert(text.baseAddr, filename.substr(fnameStart, + symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart, extStart-fnameStart) + "_start"); return true; } bool -RawObject::loadLocalSymbols(SymbolTable *symtab) +RawObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) { int fnameStart = filename.rfind('/',filename.size()) + 1; int extStart = filename.rfind('.',filename.size()); - symtab->insert(text.baseAddr, filename.substr(fnameStart, + symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart, extStart-fnameStart) + "_start"); return true; } diff --git a/src/base/loader/raw_object.hh b/src/base/loader/raw_object.hh index c7fff4e66..9014a2d30 100644 --- a/src/base/loader/raw_object.hh +++ b/src/base/loader/raw_object.hh @@ -41,8 +41,10 @@ class RawObject: public ObjectFile public: virtual ~RawObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = + std::numeric_limits<Addr>::max()); static ObjectFile *tryFile(const std::string &fname, int fd, size_t len, uint8_t *data); diff --git a/src/base/range_map.hh b/src/base/range_map.hh new file mode 100644 index 000000000..6d3450739 --- /dev/null +++ b/src/base/range_map.hh @@ -0,0 +1,246 @@ +/* + * 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 __BASE_RANGE_MAP_HH__ +#define __BASE_RANGE_MAP_HH__ + +#include "base/range.hh" + +#include <map> + +template <class T,class V> +class range_map +{ + private: + typedef std::map<Range<T>,V> RangeMap; + RangeMap tree; + + public: + typedef typename RangeMap::iterator iterator; + + template <class U> + const iterator find(const Range<U> &r) + { + iterator i; + + i = tree.upper_bound(r); + + if (i == tree.begin()) { + if (i->first.start <= r.end && i->first.end >= r.start) + return i; + else + // Nothing could match, so return end() + return tree.end(); + } + + i--; + + if (i->first.start <= r.end && i->first.end >= r.start) + return i; + + return tree.end(); + } + + template <class U> + bool intersect(const Range<U> &r) + { + iterator i; + i = find(r); + if (i != tree.end()) + return true; + return false; + } + + + template <class U,class W> + iterator insert(const Range<U> &r, const W d) + { + if (intersect(r)) + return tree.end(); + + return tree.insert(std::make_pair<Range<T>,V>(r, d)).first; + } + + size_t erase(T 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(); + } +}; + + +template <class T,class V> +class range_multimap +{ + private: + typedef std::multimap<Range<T>,V> RangeMap; + RangeMap tree; + + public: + typedef typename RangeMap::iterator iterator; + + template <class U> + std::pair<iterator,iterator> find(const Range<U> &r) + { + iterator i; + iterator j; + + i = tree.lower_bound(r); + + if (i == tree.begin()) { + if (i->first.start <= r.end && i->first.end >= r.start) + return std::make_pair<iterator, iterator>(i,i); + else + // Nothing could match, so return end() + return std::make_pair<iterator, iterator>(tree.end(), tree.end()); + } + i--; + + if (i->first.start <= r.end && i->first.end >= r.start) { + // we have at least one match + j = i; + + i--; + while (i->first.start <= r.end && i->first.end >= + r.start) { + if (i == tree.begin()) + break; + i--; + } + if (i == tree.begin() && i->first.start <= r.end && i->first.end >= + r.start) + return std::make_pair<iterator, iterator>(i,j); + i++; + return std::make_pair<iterator, iterator>(i,j); + + } + + return std::make_pair<iterator, iterator>(tree.end(), tree.end()); + } + + template <class U> + bool intersect(const Range<U> &r) + { + std::pair<iterator,iterator> p; + p = find(r); + if (p.first != tree.end()) + return true; + return false; + } + + + template <class U,class W> + iterator insert(const Range<U> &r, const W d) + { + std::pair<iterator,iterator> p; + p = find(r); + if (p.first->first.start == r.start && p.first->first.end == r.end || + p.first == tree.end()) + return tree.insert(std::make_pair<Range<T>,V>(r, d)); + else + return tree.end(); + } + + size_t erase(T 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 //__BASE_RANGE_MAP_HH__ diff --git a/src/base/traceflags.py b/src/base/traceflags.py index 92735aa5f..c06399f81 100644 --- a/src/base/traceflags.py +++ b/src/base/traceflags.py @@ -109,6 +109,7 @@ baseFlags = [ 'IIC', 'IICMore', 'IPI', + 'IPR', 'IQ', 'ISP', 'IdeCtrl', diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 7cbbb0b96..31604ad58 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -96,7 +96,7 @@ CPUProgressEvent::description() #if FULL_SYSTEM BaseCPU::BaseCPU(Params *p) - : MemObject(p->name), clock(p->clock), checkInterrupts(true), + : MemObject(p->name), clock(p->clock), instCnt(0), checkInterrupts(true), params(p), number_of_threads(p->numberOfThreads), system(p->system), phase(p->phase) #else diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 1d9b6a93b..8c6b079da 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -70,12 +70,16 @@ class BaseCPU : public MemObject protected: // CPU's clock period in terms of the number of ticks of curTime. Tick clock; + // @todo remove me after debugging with legion done + Tick instCnt; public: // Tick currentTick; inline Tick frequency() const { return Clock::Frequency / clock; } inline Tick cycles(int numCycles) const { return clock * numCycles; } inline Tick curCycle() const { return curTick / clock; } + // @todo remove me after debugging with legion done + Tick instCount() { return instCnt; } /** The next cycle the CPU should be scheduled, given a cache * access or quiesce event returning on this cycle. This function diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 780a0c4f7..98e75d83a 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -57,6 +57,10 @@ using namespace std; using namespace TheISA; +#if THE_ISA == SPARC_ISA && FULL_SYSTEM +static int diffcount = 0; +#endif + namespace Trace { SharedData *shared_data = NULL; } @@ -281,12 +285,13 @@ Trace::InstRecord::dump(ostream &outs) // outs << endl; } -#if THE_ISA == SPARC_ISA +#if THE_ISA == SPARC_ISA && FULL_SYSTEM // Compare if (flags[LEGION_LOCKSTEP]) { bool compared = false; bool diffPC = false; + bool diffCC = false; bool diffInst = false; bool diffRegs = false; bool diffTpc = false; @@ -319,6 +324,11 @@ Trace::InstRecord::dump(ostream &outs) lgnPc = shared_data->pc & TheISA::PAddrImplMask; if (lgnPc != m5Pc) diffPC = true; + + if (shared_data->cycle_count != + thread->getCpuPtr()->instCount()) + diffCC = true; + if (shared_data->instruction != (SparcISA::MachInst)staticInst->machInst) { diffInst = true; @@ -334,19 +344,19 @@ Trace::InstRecord::dump(ostream &outs) for (int i = 1; i <= MaxTL; i++) { thread->setMiscReg(MISCREG_TL, i); if (thread->readMiscReg(MISCREG_TPC) != - shared_data->tpc[i]) + shared_data->tpc[i-1]) diffTpc = true; if (thread->readMiscReg(MISCREG_TNPC) != - shared_data->tnpc[i]) + shared_data->tnpc[i-1]) diffTnpc = true; if (thread->readMiscReg(MISCREG_TSTATE) != - shared_data->tstate[i]) + shared_data->tstate[i-1]) diffTstate = true; if (thread->readMiscReg(MISCREG_TT) != - shared_data->tt[i]) + shared_data->tt[i-1]) diffTt = true; if (thread->readMiscReg(MISCREG_HTSTATE) != - shared_data->htstate[i]) + shared_data->htstate[i-1]) diffHtstate = true; } thread->setMiscReg(MISCREG_TL, oldTl); @@ -399,15 +409,18 @@ Trace::InstRecord::dump(ostream &outs) thread->readMiscReg(NumIntArchRegs + 6)) diffCleanwin = true; - if (diffPC || diffInst || diffRegs || diffTpc || diffTnpc || - diffTstate || diffTt || diffHpstate || + if ((diffPC || diffCC || diffInst || diffRegs || diffTpc || + diffTnpc || diffTstate || diffTt || diffHpstate || diffHtstate || diffHtba || diffPstate || diffY || diffCcr || diffTl || diffGl || diffAsi || diffPil || diffCwp || diffCansave || diffCanrestore || - diffOtherwin || diffCleanwin) { + diffOtherwin || diffCleanwin) + && !((staticInst->machInst & 0xC1F80000) == 0x81D00000)) { outs << "Differences found between M5 and Legion:"; if (diffPC) outs << " [PC]"; + if (diffCC) + outs << " [CC]"; if (diffInst) outs << " [Instruction]"; if (diffRegs) @@ -459,6 +472,13 @@ Trace::InstRecord::dump(ostream &outs) << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex << lgnPc << endl << endl; + outs << right << setfill(' ') << setw(15) + << "M5 CC: " << "0x"<< setw(16) << setfill('0') + << hex << thread->getCpuPtr()->instCount() << endl; + outs << setfill(' ') << setw(15) + << "Legion CC: " << "0x"<< setw(16) << setfill('0') << hex + << shared_data->cycle_count << endl << endl; + outs << setfill(' ') << setw(15) << "M5 Inst: " << "0x"<< setw(8) << setfill('0') << hex << staticInst->machInst @@ -532,19 +552,19 @@ Trace::InstRecord::dump(ostream &outs) thread->setMiscReg(MISCREG_TL, i); printRegPair(outs, "Tpc", thread->readMiscReg(MISCREG_TPC), - shared_data->tpc[i]); + shared_data->tpc[i-1]); printRegPair(outs, "Tnpc", thread->readMiscReg(MISCREG_TNPC), - shared_data->tnpc[i]); + shared_data->tnpc[i-1]); printRegPair(outs, "Tstate", thread->readMiscReg(MISCREG_TSTATE), - shared_data->tstate[i]); + shared_data->tstate[i-1]); printRegPair(outs, "Tt", thread->readMiscReg(MISCREG_TT), - shared_data->tt[i]); + shared_data->tt[i-1]); printRegPair(outs, "Htstate", thread->readMiscReg(MISCREG_HTSTATE), - shared_data->htstate[i]); + shared_data->htstate[i-1]); } thread->setMiscReg(MISCREG_TL, oldTl); outs << endl; @@ -573,7 +593,12 @@ Trace::InstRecord::dump(ostream &outs) << endl;*/ } } - fatal("Differences found between Legion and M5\n"); + thread->getITBPtr()->dumpAll(); + thread->getDTBPtr()->dumpAll(); + + diffcount++; + if (diffcount > 2) + fatal("Differences found between Legion and M5\n"); } compared = true; diff --git a/src/cpu/m5legion_interface.h b/src/cpu/m5legion_interface.h index 373fbeb11..bfb88485a 100644 --- a/src/cpu/m5legion_interface.h +++ b/src/cpu/m5legion_interface.h @@ -30,7 +30,7 @@ #include <unistd.h> -#define VERSION 0xA1000005 +#define VERSION 0xA1000006 #define OWN_M5 0x000000AA #define OWN_LEGION 0x00000055 @@ -42,6 +42,8 @@ typedef struct { uint64_t pc; uint64_t new_pc; + uint64_t cycle_count; + uint64_t new_cycle_count; uint32_t instruction; uint32_t new_instruction; uint64_t intregs[32]; diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index 7bf34d827..264309fd7 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -116,7 +116,7 @@ class MemTest : public MemObject virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } }; CpuPort cachePort; diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 4f5a161e0..0371cd2bc 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -98,7 +98,7 @@ class DefaultFetch /** Returns the address ranges of this device. */ virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } /** Timing version of receive. Handles setting fetch to the * proper status to start fetching. */ diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 24c8484b4..70200d648 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -528,6 +528,7 @@ DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, unsigned tid) #if ISA_HAS_DELAY_SLOT toCommit->nextNPC[tid] = inst->readNextNPC(); #endif + toCommit->branchMispredict[tid] = false; toCommit->includeSquashInst[tid] = false; @@ -547,6 +548,7 @@ DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, unsigned tid) #if ISA_HAS_DELAY_SLOT toCommit->nextNPC[tid] = inst->readNextNPC(); #endif + toCommit->branchMispredict[tid] = false; // Must include the broadcasted SN in the squash. toCommit->includeSquashInst[tid] = true; @@ -1308,7 +1310,8 @@ DefaultIEW<Impl>::executeInsts() } else if (fault != NoFault) { // If the instruction faulted, then we need to send it along to commit // without the instruction completing. - DPRINTF(IEW, "Store has fault! [sn:%lli]\n", inst->seqNum); + DPRINTF(IEW, "Store has fault %s! [sn:%lli]\n", + fault->name(), inst->seqNum); // Send this instruction to commit, also make sure iew stage // realizes there is activity. @@ -1345,7 +1348,8 @@ DefaultIEW<Impl>::executeInsts() // instruction first, so the branch resolution order will be correct. unsigned tid = inst->threadNumber; - if (!fetchRedirect[tid]) { + if (!fetchRedirect[tid] || + toCommit->squashedSeqNum[tid] > inst->seqNum) { if (inst->mispredicted()) { fetchRedirect[tid] = true; @@ -1368,8 +1372,6 @@ DefaultIEW<Impl>::executeInsts() predictedNotTakenIncorrect++; } } else if (ldstQueue.violation(tid)) { - fetchRedirect[tid] = true; - // If there was an ordering violation, then get the // DynInst that caused the violation. Note that this // clears the violation signal. @@ -1380,6 +1382,14 @@ DefaultIEW<Impl>::executeInsts() "%#x, inst PC: %#x. Addr is: %#x.\n", violator->readPC(), inst->readPC(), inst->physEffAddr); + // Ensure the violating instruction is older than + // current squash + if (fetchRedirect[tid] && + violator->seqNum >= toCommit->squashedSeqNum[tid]) + continue; + + fetchRedirect[tid] = true; + // Tell the instruction queue that a violation has occured. instQueue.violation(inst, violator); diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 7559a36d5..e68085cfd 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -313,7 +313,7 @@ class LSQ { /** Returns the address ranges of this device. */ virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } /** Timing version of receive. Handles writing back and * completing the load or store that has returned from diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh index e09e4de9c..0acf99ead 100644 --- a/src/cpu/ozone/front_end.hh +++ b/src/cpu/ozone/front_end.hh @@ -92,7 +92,7 @@ class FrontEnd /** Returns the address ranges of this device. */ virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } /** Timing version of receive. Handles setting fetch to the * proper status to start fetching. */ diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh index 7e6849668..c981b8e63 100644 --- a/src/cpu/ozone/lw_lsq.hh +++ b/src/cpu/ozone/lw_lsq.hh @@ -258,7 +258,7 @@ class OzoneLWLSQ { virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } virtual bool recvTiming(PacketPtr pkt); diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 8cfe2ee83..8db864153 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -29,6 +29,7 @@ */ #include "arch/locked_mem.hh" +#include "arch/mmaped_ipr.hh" #include "arch/utility.hh" #include "cpu/exetrace.hh" #include "cpu/simple/atomic.hh" @@ -289,10 +290,16 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) if (fault == NoFault) { pkt->reinitFromRequest(); - dcache_latency = dcachePort.sendAtomic(pkt); + if (req->isMmapedIpr()) + dcache_latency = TheISA::handleIprRead(thread->getTC(),pkt); + else + dcache_latency = dcachePort.sendAtomic(pkt); dcache_access = true; - - assert(pkt->result == Packet::Success); +#if !defined(NDEBUG) + if (pkt->result != Packet::Success) + panic("Unable to find responder for address pa = %#X va = %#X\n", + pkt->req->getPaddr(), pkt->req->getVaddr()); +#endif data = pkt->get<T>(); if (req->isLocked()) { @@ -376,14 +383,22 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) } if (do_access) { - data = htog(data); pkt->reinitFromRequest(); pkt->dataStatic(&data); - dcache_latency = dcachePort.sendAtomic(pkt); + if (req->isMmapedIpr()) { + dcache_latency = TheISA::handleIprWrite(thread->getTC(), pkt); + } else { + data = htog(data); + dcache_latency = dcachePort.sendAtomic(pkt); + } dcache_access = true; - assert(pkt->result == Packet::Success); +#if !defined(NDEBUG) + if (pkt->result != Packet::Success) + panic("Unable to find responder for address pa = %#X va = %#X\n", + pkt->req->getPaddr(), pkt->req->getVaddr()); +#endif } if (req->isLocked()) { @@ -476,9 +491,15 @@ AtomicSimpleCPU::tick() dcache_access = false; // assume no dcache access preExecute(); + fault = curStaticInst->execute(this, traceData); postExecute(); + // @todo remove me after debugging with legion done + if (curStaticInst && (!curStaticInst->isMicroOp() || + curStaticInst->isLastMicroOp())) + instCnt++; + if (simulate_stalls) { Tick icache_stall = icache_latency - cycles(1); Tick dcache_stall = diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 0df6fe079..42c7bf23a 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -106,7 +106,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } }; CpuPort icachePort; diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index fe5d03666..abcb224bf 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -94,7 +94,7 @@ class TimingSimpleCPU : public BaseSimpleCPU virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,-1)); } + { resp.clear(); snoop.clear(); snoop.push_back(RangeSize(0,0)); } struct TickEvent : public Event { diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc index 924e1d462..eb51d4e49 100644 --- a/src/dev/alpha/tsunami_cchip.cc +++ b/src/dev/alpha/tsunami_cchip.cc @@ -57,7 +57,7 @@ using namespace TheISA; TsunamiCChip::TsunamiCChip(Params *p) : BasicPioDevice(p), tsunami(p->tsunami) { - pioSize = 0xfffffff; + pioSize = 0x10000000; drir = 0; ipint = 0; diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc index def214a95..8430856ef 100644 --- a/src/dev/alpha/tsunami_io.cc +++ b/src/dev/alpha/tsunami_io.cc @@ -430,7 +430,7 @@ TsunamiIO::TsunamiIO(Params *p) : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), rtc(p->name + ".rtc", p->tsunami, p->frequency) { - pioSize = 0xff; + pioSize = 0x100; // set the back pointer from tsunami to myself tsunami->io = this; diff --git a/src/dev/alpha/tsunami_pchip.cc b/src/dev/alpha/tsunami_pchip.cc index 94a7f96e5..f30199337 100644 --- a/src/dev/alpha/tsunami_pchip.cc +++ b/src/dev/alpha/tsunami_pchip.cc @@ -53,7 +53,7 @@ using namespace TheISA; TsunamiPChip::TsunamiPChip(Params *p) : BasicPioDevice(p) { - pioSize = 0xfff; + pioSize = 0x1000; for (int i = 0; i < 4; i++) { wsba[i] = 0; diff --git a/src/dev/baddev.cc b/src/dev/baddev.cc index 1bab93492..6a7060455 100644 --- a/src/dev/baddev.cc +++ b/src/dev/baddev.cc @@ -49,7 +49,7 @@ using namespace TheISA; BadDevice::BadDevice(Params *p) : BasicPioDevice(p), devname(p->device_name) { - pioSize = 0xf; + pioSize = 0x10; } Tick diff --git a/src/dev/isa_fake.cc b/src/dev/isa_fake.cc index 40909c6a1..c36ddeb83 100644 --- a/src/dev/isa_fake.cc +++ b/src/dev/isa_fake.cc @@ -47,7 +47,10 @@ IsaFake::IsaFake(Params *p) if (!params()->retBadAddr) pioSize = p->pio_size; - memset(&retData, p->retData, sizeof(retData)); + retData8 = params()->retData8; + retData16 = params()->retData16; + retData32 = params()->retData32; + retData64 = params()->retData64; } Tick @@ -55,6 +58,9 @@ IsaFake::read(PacketPtr pkt) { assert(pkt->result == Packet::Unknown); + if (params()->warnAccess != "") + warn("Device %s accessed by read to address %#x size=%d\n", + name(), pkt->getAddr(), pkt->getSize()); if (params()->retBadAddr) { DPRINTF(Tsunami, "read to bad address va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); @@ -65,16 +71,16 @@ IsaFake::read(PacketPtr pkt) pkt->getAddr(), pkt->getSize()); switch (pkt->getSize()) { case sizeof(uint64_t): - pkt->set(retData); + pkt->set(retData64); break; case sizeof(uint32_t): - pkt->set((uint32_t)retData); + pkt->set(retData32); break; case sizeof(uint16_t): - pkt->set((uint16_t)retData); + pkt->set(retData16); break; case sizeof(uint8_t): - pkt->set((uint8_t)retData); + pkt->set(retData8); break; default: panic("invalid access size!\n"); @@ -87,6 +93,27 @@ IsaFake::read(PacketPtr pkt) Tick IsaFake::write(PacketPtr pkt) { + if (params()->warnAccess != "") { + uint64_t data; + switch (pkt->getSize()) { + case sizeof(uint64_t): + data = pkt->get<uint64_t>(); + break; + case sizeof(uint32_t): + data = pkt->get<uint32_t>(); + break; + case sizeof(uint16_t): + data = pkt->get<uint16_t>(); + break; + case sizeof(uint8_t): + data = pkt->get<uint8_t>(); + break; + default: + panic("invalid access size!\n"); + } + warn("Device %s accessed by write to address %#x size=%d data=%#x\n", + name(), pkt->getAddr(), pkt->getSize(), data); + } if (params()->retBadAddr) { DPRINTF(Tsunami, "write to bad address va=%#x size=%d \n", pkt->getAddr(), pkt->getSize()); @@ -94,6 +121,25 @@ IsaFake::write(PacketPtr pkt) } else { DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize()); + + if (params()->updateData) { + switch (pkt->getSize()) { + case sizeof(uint64_t): + retData64 = pkt->get<uint64_t>(); + break; + case sizeof(uint32_t): + retData32 = pkt->get<uint32_t>(); + break; + case sizeof(uint16_t): + retData16 = pkt->get<uint16_t>(); + break; + case sizeof(uint8_t): + retData8 = pkt->get<uint8_t>(); + break; + default: + panic("invalid access size!\n"); + } + } pkt->result = Packet::Success; } return pioDelay; @@ -105,7 +151,12 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake) Param<Tick> pio_latency; Param<Addr> pio_size; Param<bool> ret_bad_addr; - Param<uint8_t> ret_data; + Param<bool> update_data; + Param<std::string> warn_access; + Param<uint8_t> ret_data8; + Param<uint16_t> ret_data16; + Param<uint32_t> ret_data32; + Param<uint64_t> ret_data64; SimObjectParam<Platform *> platform; SimObjectParam<System *> system; @@ -117,7 +168,12 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake) INIT_PARAM(pio_latency, "Programmed IO latency"), INIT_PARAM(pio_size, "Size of address range"), INIT_PARAM(ret_bad_addr, "Return pkt status BadAddr"), - INIT_PARAM(ret_data, "Data to return if not bad addr"), + INIT_PARAM(update_data, "Update returned data"), + INIT_PARAM(warn_access, "Warn if this device is touched"), + INIT_PARAM(ret_data8, "Data to return if not bad addr"), + INIT_PARAM(ret_data16, "Data to return if not bad addr"), + INIT_PARAM(ret_data32, "Data to return if not bad addr"), + INIT_PARAM(ret_data64, "Data to return if not bad addr"), INIT_PARAM(platform, "platform"), INIT_PARAM(system, "system object") @@ -131,7 +187,12 @@ CREATE_SIM_OBJECT(IsaFake) p->pio_delay = pio_latency; p->pio_size = pio_size; p->retBadAddr = ret_bad_addr; - p->retData = ret_data; + p->updateData = update_data; + p->warnAccess = warn_access; + p->retData8= ret_data8; + p->retData16 = ret_data16; + p->retData32 = ret_data32; + p->retData64 = ret_data64; p->platform = platform; p->system = system; return new IsaFake(p); diff --git a/src/dev/isa_fake.hh b/src/dev/isa_fake.hh index fee41e325..dc2ad48e8 100644 --- a/src/dev/isa_fake.hh +++ b/src/dev/isa_fake.hh @@ -40,6 +40,8 @@ #include "dev/alpha/tsunami.hh" #include "mem/packet.hh" +#include <string> + /** * IsaFake is a device that returns, BadAddr, 1 or 0 on all reads and * rites. It is meant to be placed at an address range @@ -54,11 +56,20 @@ class IsaFake : public BasicPioDevice { Addr pio_size; bool retBadAddr; - uint8_t retData; + bool updateData; + uint8_t retData8; + uint16_t retData16; + uint32_t retData32; + uint64_t retData64; + std::string warnAccess; }; protected: const Params *params() const { return (const Params*)_params; } - uint64_t retData; + uint8_t retData8; + uint16_t retData16; + uint32_t retData32; + uint64_t retData64; + public: /** diff --git a/src/dev/sparc/t1000.cc b/src/dev/sparc/t1000.cc index 1df6bf15f..4a8de77a5 100644 --- a/src/dev/sparc/t1000.cc +++ b/src/dev/sparc/t1000.cc @@ -56,50 +56,58 @@ T1000::T1000(const string &name, System *s, IntrControl *ic) Tick T1000::intrFrequency() { - return (Tick)0; + panic("Need implementation\n"); } void T1000::postConsoleInt() { + warn_once("Don't know what interrupt to post for console.\n"); + //panic("Need implementation\n"); } void T1000::clearConsoleInt() { + warn_once("Don't know what interrupt to clear for console.\n"); + //panic("Need implementation\n"); } void T1000::postPciInt(int line) { + panic("Need implementation\n"); } void T1000::clearPciInt(int line) { + panic("Need implementation\n"); } Addr T1000::pciToDma(Addr pciAddr) const { - return (Addr)0; + panic("Need implementation\n"); } Addr T1000::calcConfigAddr(int bus, int dev, int func) { - return (Addr)0; + panic("Need implementation\n"); } void T1000::serialize(std::ostream &os) { + panic("Need implementation\n"); } void T1000::unserialize(Checkpoint *cp, const std::string §ion) { + panic("Need implementation\n"); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(T1000) diff --git a/src/dev/sparc/t1000.hh b/src/dev/sparc/t1000.hh index fb82dff11..2955763a9 100644 --- a/src/dev/sparc/t1000.hh +++ b/src/dev/sparc/t1000.hh @@ -30,7 +30,7 @@ /** * @file - * Declaration of top level class for the Tsunami chipset. This class just + * Declaration of top level class for the T1000 platform chips. This class just * retains pointers to all its children so the children can communicate. */ @@ -69,7 +69,7 @@ class T1000 : public Platform virtual void postConsoleInt(); /** - * Clear a posted CPU interrupt (id=55) + * Clear a posted CPU interrupt */ virtual void clearConsoleInt(); diff --git a/src/mem/bus.cc b/src/mem/bus.cc index e9a870b80..bd721dd68 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -260,19 +260,12 @@ Bus::findPort(Addr addr, int id) { /* An interval tree would be a better way to do this. --ali. */ int dest_id = -1; - int i = 0; - bool found = false; AddrRangeIter iter; + range_map<Addr,int>::iterator i; - while (i < portList.size() && !found) - { - if (portList[i].range == addr) { - dest_id = portList[i].portId; - found = true; - DPRINTF(Bus, " found addr %#llx on device %d\n", addr, dest_id); - } - i++; - } + i = portMap.find(RangeSize(addr,1)); + if (i != portMap.end()) + dest_id = i->second; // Check if this matches the default range if (dest_id == -1) { @@ -463,13 +456,13 @@ Bus::recvStatusChange(Port::Status status, int id) assert((id < interfaces.size() && id >= 0) || id == defaultId); Port *port = interfaces[id]; - std::vector<DevMap>::iterator portIter; + range_map<Addr,int>::iterator portIter; std::vector<DevMap>::iterator snoopIter; // Clean out any previously existent ids - for (portIter = portList.begin(); portIter != portList.end(); ) { - if (portIter->portId == id) - portIter = portList.erase(portIter); + for (portIter = portMap.begin(); portIter != portMap.end(); ) { + if (portIter->second == id) + portMap.erase(portIter++); else portIter++; } @@ -495,16 +488,14 @@ Bus::recvStatusChange(Port::Status status, int id) } for(iter = ranges.begin(); iter != ranges.end(); iter++) { - DevMap dm; - dm.portId = id; - dm.range = *iter; - DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", - dm.range.start, dm.range.end, id); - portList.push_back(dm); + iter->start, iter->end, id); + if (portMap.insert(*iter, id) == portMap.end()) + panic("Two devices with same range\n"); + } } - DPRINTF(MMU, "port list has %d entries\n", portList.size()); + DPRINTF(MMU, "port list has %d entries\n", portMap.size()); // tell all our peers that our address range has changed. // Don't tell the device that caused this change, it already knows @@ -519,7 +510,8 @@ Bus::recvStatusChange(Port::Status status, int id) void Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) { - std::vector<DevMap>::iterator portIter; + std::vector<DevMap>::iterator snoopIter; + range_map<Addr,int>::iterator portIter; AddrRangeIter dflt_iter; bool subset; @@ -534,37 +526,37 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, dflt_iter->end); } - for (portIter = portList.begin(); portIter != portList.end(); portIter++) { + for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) { subset = false; for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); dflt_iter++) { - if ((portIter->range.start < dflt_iter->start && - portIter->range.end >= dflt_iter->start) || - (portIter->range.start < dflt_iter->end && - portIter->range.end >= dflt_iter->end)) + if ((portIter->first.start < dflt_iter->start && + portIter->first.end >= dflt_iter->start) || + (portIter->first.start < dflt_iter->end && + portIter->first.end >= dflt_iter->end)) fatal("Devices can not set ranges that itersect the default set\ but are not a subset of the default set.\n"); - if (portIter->range.start >= dflt_iter->start && - portIter->range.end <= dflt_iter->end) { + if (portIter->first.start >= dflt_iter->start && + portIter->first.end <= dflt_iter->end) { subset = true; DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", - portIter->range.start, portIter->range.end); + portIter->first.start, portIter->first.end); } } - if (portIter->portId != id && !subset) { - resp.push_back(portIter->range); + if (portIter->second != id && !subset) { + resp.push_back(portIter->first); DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", - portIter->range.start, portIter->range.end); + portIter->first.start, portIter->first.end); } } - for (portIter = portSnoopList.begin(); - portIter != portSnoopList.end(); portIter++) + for (snoopIter = portSnoopList.begin(); + snoopIter != portSnoopList.end(); snoopIter++) { - if (portIter->portId != id) { - snoop.push_back(portIter->range); + if (snoopIter->portId != id) { + snoop.push_back(snoopIter->range); DPRINTF(BusAddrRanges, " -- Snoop: %#llx : %#llx\n", - portIter->range.start, portIter->range.end); + snoopIter->range.start, snoopIter->range.end); //@todo We need to properly insert snoop ranges //not overlapping the ranges (multiple) } diff --git a/src/mem/bus.hh b/src/mem/bus.hh index c472b6143..0ad4aad60 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -42,6 +42,7 @@ #include <inttypes.h> #include "base/range.hh" +#include "base/range_map.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" #include "mem/port.hh" @@ -67,7 +68,7 @@ class Bus : public MemObject int portId; Range<Addr> range; }; - std::vector<DevMap> portList; + range_map<Addr, int> portMap; AddrRangeList defaultRange; std::vector<DevMap> portSnoopList; diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc index 3af61375d..d9e6c5e1f 100644 --- a/src/mem/cache/base_cache.cc +++ b/src/mem/cache/base_cache.cc @@ -51,6 +51,7 @@ BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache, //memSidePort = NULL; } + void BaseCache::CachePort::recvStatusChange(Port::Status status) { @@ -71,38 +72,6 @@ BaseCache::CachePort::deviceBlockSize() } bool -BaseCache::CachePort::recvTiming(PacketPtr pkt) -{ - if (isCpuSide - && !pkt->req->isUncacheable() - && pkt->isInvalidate() - && !pkt->isRead() && !pkt->isWrite()) { - //Upgrade or Invalidate - //Look into what happens if two slave caches on bus - DPRINTF(Cache, "%s %x ?\n", pkt->cmdString(), pkt->getAddr()); - - assert(!(pkt->flags & SATISFIED)); - pkt->flags |= SATISFIED; - //Invalidates/Upgrades need no response if they get the bus - return true; - } - - if (pkt->isRequest() && blocked) - { - DPRINTF(Cache,"Scheduling a retry while blocked\n"); - mustSendRetry = true; - return false; - } - return cache->doTimingAccess(pkt, this, isCpuSide); -} - -Tick -BaseCache::CachePort::recvAtomic(PacketPtr pkt) -{ - return cache->doAtomicAccess(pkt, isCpuSide); -} - -bool BaseCache::CachePort::checkFunctional(PacketPtr pkt) { //Check storage here first @@ -139,14 +108,6 @@ BaseCache::CachePort::checkFunctional(PacketPtr pkt) } void -BaseCache::CachePort::recvFunctional(PacketPtr pkt) -{ - bool notDone = checkFunctional(pkt); - if (notDone) - cache->doFunctionalAccess(pkt, isCpuSide); -} - -void BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt) { bool notDone = checkFunctional(pkt); @@ -398,40 +359,6 @@ BaseCache::CacheEvent::description() return "timing event\n"; } -Port* -BaseCache::getPort(const std::string &if_name, int idx) -{ - if (if_name == "") - { - if(cpuSidePort == NULL) { - cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true); - sendEvent = new CacheEvent(cpuSidePort, true); - } - return cpuSidePort; - } - else if (if_name == "functional") - { - return new CachePort(name() + "-cpu_side_port", this, true); - } - else if (if_name == "cpu_side") - { - if(cpuSidePort == NULL) { - cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true); - sendEvent = new CacheEvent(cpuSidePort, true); - } - return cpuSidePort; - } - else if (if_name == "mem_side") - { - if (memSidePort != NULL) - panic("Already have a mem side for this cache\n"); - memSidePort = new CachePort(name() + "-mem_side_port", this, false); - memSendEvent = new CacheEvent(memSidePort, true); - return memSidePort; - } - else panic("Port name %s unrecognized\n", if_name); -} - void BaseCache::init() { diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh index ef4955432..a7f035dce 100644 --- a/src/mem/cache/base_cache.hh +++ b/src/mem/cache/base_cache.hh @@ -82,15 +82,8 @@ class BaseCache : public MemObject public: BaseCache *cache; - CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide); - protected: - virtual bool recvTiming(PacketPtr pkt); - - virtual Tick recvAtomic(PacketPtr pkt); - - virtual void recvFunctional(PacketPtr pkt); - + CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide); virtual void recvStatusChange(Status status); virtual void getDeviceAddressRanges(AddrRangeList &resp, @@ -137,33 +130,12 @@ class BaseCache : public MemObject public: //Made public so coherence can get at it. CachePort *cpuSidePort; + CachePort *memSidePort; CacheEvent *sendEvent; CacheEvent *memSendEvent; - protected: - CachePort *memSidePort; - - public: - virtual Port *getPort(const std::string &if_name, int idx = -1); - private: - //To be defined in cache_impl.hh not in base class - virtual bool doTimingAccess(PacketPtr pkt, CachePort *cachePort, bool isCpuSide) - { - fatal("No implementation"); - } - - virtual Tick doAtomicAccess(PacketPtr pkt, bool isCpuSide) - { - fatal("No implementation"); - } - - virtual void doFunctionalAccess(PacketPtr pkt, bool isCpuSide) - { - fatal("No implementation"); - } - void recvStatusChange(Port::Status status, bool isCpuSide) { if (status == Port::RangeChange){ @@ -176,27 +148,13 @@ class BaseCache : public MemObject } } - virtual PacketPtr getPacket() - { - fatal("No implementation"); - } + virtual PacketPtr getPacket() = 0; - virtual PacketPtr getCoherencePacket() - { - fatal("No implementation"); - } - - virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success) - { + virtual PacketPtr getCoherencePacket() = 0; - fatal("No implementation"); - } + virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success) = 0; - virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success) - { - - fatal("No implementation"); - } + virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success) = 0; /** * Bit vector of the blocking reasons for the access path. diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index 29502042c..097b0f513 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -64,8 +64,49 @@ class Cache : public BaseCache typedef typename TagStore::BlkType BlkType; bool prefetchAccess; + protected: + class CpuSidePort : public CachePort + { + public: + CpuSidePort(const std::string &_name, + Cache<TagStore,Coherence> *_cache); + + // BaseCache::CachePort just has a BaseCache *; this function + // lets us get back the type info we lost when we stored the + // cache pointer there. + Cache<TagStore,Coherence> *myCache() { + return static_cast<Cache<TagStore,Coherence> *>(cache); + } + + virtual bool recvTiming(PacketPtr pkt); + + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvFunctional(PacketPtr pkt); + }; + + class MemSidePort : public CachePort + { + public: + MemSidePort(const std::string &_name, + Cache<TagStore,Coherence> *_cache); + + // BaseCache::CachePort just has a BaseCache *; this function + // lets us get back the type info we lost when we stored the + // cache pointer there. + Cache<TagStore,Coherence> *myCache() { + return static_cast<Cache<TagStore,Coherence> *>(cache); + } + + virtual bool recvTiming(PacketPtr pkt); + + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvFunctional(PacketPtr pkt); + }; + /** Tag and data Storage */ TagStore *tags; /** Miss and Writeback handler */ @@ -128,12 +169,7 @@ class Cache : public BaseCache /** Instantiates a basic cache object. */ Cache(const std::string &_name, Params ¶ms); - virtual bool doTimingAccess(PacketPtr pkt, CachePort *cachePort, - bool isCpuSide); - - virtual Tick doAtomicAccess(PacketPtr pkt, bool isCpuSide); - - virtual void doFunctionalAccess(PacketPtr pkt, bool isCpuSide); + virtual Port *getPort(const std::string &if_name, int idx = -1); virtual void recvStatusChange(Port::Status status, bool isCpuSide); diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 6742d5892..9f48ff1f3 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -56,74 +56,6 @@ bool SIGNAL_NACK_HACK; template<class TagStore, class Coherence> -bool -Cache<TagStore,Coherence>:: -doTimingAccess(PacketPtr pkt, CachePort *cachePort, bool isCpuSide) -{ - if (isCpuSide) - { - if (pkt->isWrite() && (pkt->req->isLocked())) { - pkt->req->setScResult(1); - } - access(pkt); - - } - else - { - if (pkt->isResponse()) - handleResponse(pkt); - else { - //Check if we should do the snoop - if (pkt->flags & SNOOP_COMMIT) - snoop(pkt); - } - } - return true; -} - -template<class TagStore, class Coherence> -Tick -Cache<TagStore,Coherence>:: -doAtomicAccess(PacketPtr pkt, bool isCpuSide) -{ - if (isCpuSide) - { - probe(pkt, true, NULL); - //TEMP ALWAYS SUCCES FOR NOW - pkt->result = Packet::Success; - } - else - { - if (pkt->isResponse()) - handleResponse(pkt); - else - return snoopProbe(pkt); - } - //Fix this timing info - return hitLatency; -} - -template<class TagStore, class Coherence> -void -Cache<TagStore,Coherence>:: -doFunctionalAccess(PacketPtr pkt, bool isCpuSide) -{ - if (isCpuSide) - { - //TEMP USE CPU?THREAD 0 0 - pkt->req->setThreadContext(0,0); - - probe(pkt, false, memSidePort); - //TEMP ALWAYS SUCCESFUL FOR NOW - pkt->result = Packet::Success; - } - else - { - probe(pkt, false, cpuSidePort); - } -} - -template<class TagStore, class Coherence> void Cache<TagStore,Coherence>:: recvStatusChange(Port::Status status, bool isCpuSide) @@ -727,3 +659,155 @@ Cache<TagStore,Coherence>::snoopProbe(PacketPtr &pkt) return 0; } +template<class TagStore, class Coherence> +Port * +Cache<TagStore,Coherence>::getPort(const std::string &if_name, int idx) +{ + if (if_name == "") + { + if (cpuSidePort == NULL) { + cpuSidePort = new CpuSidePort(name() + "-cpu_side_port", this); + sendEvent = new CacheEvent(cpuSidePort, true); + } + return cpuSidePort; + } + else if (if_name == "functional") + { + return new CpuSidePort(name() + "-cpu_side_port", this); + } + else if (if_name == "cpu_side") + { + if (cpuSidePort == NULL) { + cpuSidePort = new CpuSidePort(name() + "-cpu_side_port", this); + sendEvent = new CacheEvent(cpuSidePort, true); + } + return cpuSidePort; + } + else if (if_name == "mem_side") + { + if (memSidePort != NULL) + panic("Already have a mem side for this cache\n"); + memSidePort = new MemSidePort(name() + "-mem_side_port", this); + memSendEvent = new CacheEvent(memSidePort, true); + return memSidePort; + } + else panic("Port name %s unrecognized\n", if_name); +} + + +template<class TagStore, class Coherence> +bool +Cache<TagStore,Coherence>::CpuSidePort::recvTiming(PacketPtr pkt) +{ + if (!pkt->req->isUncacheable() + && pkt->isInvalidate() + && !pkt->isRead() && !pkt->isWrite()) { + //Upgrade or Invalidate + //Look into what happens if two slave caches on bus + DPRINTF(Cache, "%s %x ?\n", pkt->cmdString(), pkt->getAddr()); + + assert(!(pkt->flags & SATISFIED)); + pkt->flags |= SATISFIED; + //Invalidates/Upgrades need no response if they get the bus + return true; + } + + if (pkt->isRequest() && blocked) + { + DPRINTF(Cache,"Scheduling a retry while blocked\n"); + mustSendRetry = true; + return false; + } + + if (pkt->isWrite() && (pkt->req->isLocked())) { + pkt->req->setScResult(1); + } + myCache()->access(pkt); + return true; +} + +template<class TagStore, class Coherence> +Tick +Cache<TagStore,Coherence>::CpuSidePort::recvAtomic(PacketPtr pkt) +{ + myCache()->probe(pkt, true, NULL); + //TEMP ALWAYS SUCCES FOR NOW + pkt->result = Packet::Success; + //Fix this timing info + return myCache()->hitLatency; +} + +template<class TagStore, class Coherence> +void +Cache<TagStore,Coherence>::CpuSidePort::recvFunctional(PacketPtr pkt) +{ + if (checkFunctional(pkt)) { + //TEMP USE CPU?THREAD 0 0 + pkt->req->setThreadContext(0,0); + + myCache()->probe(pkt, false, cache->memSidePort); + //TEMP ALWAYS SUCCESFUL FOR NOW + pkt->result = Packet::Success; + } +} + + +template<class TagStore, class Coherence> +bool +Cache<TagStore,Coherence>::MemSidePort::recvTiming(PacketPtr pkt) +{ + if (pkt->isRequest() && blocked) + { + DPRINTF(Cache,"Scheduling a retry while blocked\n"); + mustSendRetry = true; + return false; + } + + if (pkt->isResponse()) + myCache()->handleResponse(pkt); + else { + //Check if we should do the snoop + if (pkt->flags & SNOOP_COMMIT) + myCache()->snoop(pkt); + } + return true; +} + +template<class TagStore, class Coherence> +Tick +Cache<TagStore,Coherence>::MemSidePort::recvAtomic(PacketPtr pkt) +{ + if (pkt->isResponse()) + myCache()->handleResponse(pkt); + else + return myCache()->snoopProbe(pkt); + //Fix this timing info + return myCache()->hitLatency; +} + +template<class TagStore, class Coherence> +void +Cache<TagStore,Coherence>::MemSidePort::recvFunctional(PacketPtr pkt) +{ + if (checkFunctional(pkt)) { + myCache()->probe(pkt, false, cache->cpuSidePort); + } +} + + +template<class TagStore, class Coherence> +Cache<TagStore,Coherence>:: +CpuSidePort::CpuSidePort(const std::string &_name, + Cache<TagStore,Coherence> *_cache) + : BaseCache::CachePort(_name, _cache, true) +{ +} + +template<class TagStore, class Coherence> +Cache<TagStore,Coherence>:: +MemSidePort::MemSidePort(const std::string &_name, + Cache<TagStore,Coherence> *_cache) + : BaseCache::CachePort(_name, _cache, false) +{ +} + diff --git a/src/mem/request.hh b/src/mem/request.hh index e54984fcd..de0512e1c 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -49,26 +49,28 @@ class Request; typedef Request* RequestPtr; +/** ASI information for this request if it exsits. */ +const uint32_t ASI_BITS = 0x000FF; /** The request is a Load locked/store conditional. */ -const unsigned LOCKED = 0x001; +const uint32_t LOCKED = 0x00100; /** The virtual address is also the physical address. */ -const unsigned PHYSICAL = 0x002; +const uint32_t PHYSICAL = 0x00200; /** The request is an ALPHA VPTE pal access (hw_ld). */ -const unsigned VPTE = 0x004; +const uint32_t VPTE = 0x00400; /** Use the alternate mode bits in ALPHA. */ -const unsigned ALTMODE = 0x008; +const uint32_t ALTMODE = 0x00800; /** The request is to an uncacheable address. */ -const unsigned UNCACHEABLE = 0x010; +const uint32_t UNCACHEABLE = 0x01000; /** The request should not cause a page fault. */ -const unsigned NO_FAULT = 0x020; +const uint32_t NO_FAULT = 0x02000; /** The request should be prefetched into the exclusive state. */ -const unsigned PF_EXCLUSIVE = 0x100; +const uint32_t PF_EXCLUSIVE = 0x10000; /** The request should be marked as LRU. */ -const unsigned EVICT_NEXT = 0x200; +const uint32_t EVICT_NEXT = 0x20000; /** The request should ignore unaligned access faults */ -const unsigned NO_ALIGN_FAULT = 0x400; +const uint32_t NO_ALIGN_FAULT = 0x40000; /** The request was an instruction read. */ -const unsigned INST_READ = 0x800; +const uint32_t INST_READ = 0x80000; class Request { @@ -95,6 +97,10 @@ class Request /** The address space ID. */ int asid; + + /** This request is to a memory mapped register. */ + bool mmapedIpr; + /** The virtual address of the request. */ Addr vaddr; @@ -164,6 +170,7 @@ class Request validAsidVaddr = false; validPC = false; validScResult = false; + mmapedIpr = false; } /** @@ -181,6 +188,7 @@ class Request validAsidVaddr = true; validPC = true; validScResult = false; + mmapedIpr = false; } /** Set just the physical address. This should only be used to @@ -215,6 +223,19 @@ class Request /** Accessor function for asid.*/ int getAsid() { assert(validAsidVaddr); return asid; } + /** Accessor function for asi.*/ + uint8_t getAsi() { assert(validAsidVaddr); return flags & ASI_BITS; } + + /** Accessor function for asi.*/ + void setAsi(uint8_t a) + { assert(validAsidVaddr); flags = (flags & ~ASI_BITS) | a; } + + /** Accessor function for asi.*/ + bool isMmapedIpr() { assert(validPaddr); return mmapedIpr; } + + /** Accessor function for asi.*/ + void setMmapedIpr(bool r) { assert(validAsidVaddr); mmapedIpr = r; } + /** Accessor function to check if sc result is valid. */ bool scResultValid() { return validScResult; } /** Accessor function for store conditional return value.*/ diff --git a/src/python/m5/objects/Bus.py b/src/python/m5/objects/Bus.py index e7019f3ac..8226fe8d2 100644 --- a/src/python/m5/objects/Bus.py +++ b/src/python/m5/objects/Bus.py @@ -2,7 +2,7 @@ from m5 import build_env from m5.params import * from m5.proxy import * from MemObject import MemObject -from Tsunami import BadAddr +from Device import BadAddr class Bus(MemObject): type = 'Bus' @@ -12,7 +12,7 @@ class Bus(MemObject): width = Param.Int(64, "bus width (bytes)") responder_set = Param.Bool(False, "Did the user specify a default responder.") if build_env['FULL_SYSTEM']: - default = Port(Self.responder.pio, "Default port for requests that aren't handled by a device.") responder = BadAddr(pio_addr=0x0, pio_latency="1ps") + default = Port(Self.responder.pio, "Default port for requests that aren't handled by a device.") else: default = Port("Default port for requests that aren't handled by a device.") diff --git a/src/python/m5/objects/Device.py b/src/python/m5/objects/Device.py index 4672d1065..f4b873a60 100644 --- a/src/python/m5/objects/Device.py +++ b/src/python/m5/objects/Device.py @@ -19,3 +19,19 @@ class DmaDevice(PioDevice): type = 'DmaDevice' abstract = True dma = Port(Self.pio.peerObj.port, "DMA port") + +class IsaFake(BasicPioDevice): + type = 'IsaFake' + pio_size = Param.Addr(0x8, "Size of address range") + ret_data8 = Param.UInt8(0xFF, "Default data to return") + ret_data16 = Param.UInt16(0xFFFF, "Default data to return") + ret_data32 = Param.UInt32(0xFFFFFFFF, "Default data to return") + ret_data64 = Param.UInt64(0xFFFFFFFFFFFFFFFF, "Default data to return") + ret_bad_addr = Param.Bool(False, "Return pkt status bad address on access") + update_data = Param.Bool(False, "Update the data that is returned on writes") + warn_access = Param.String("", "String to print when device is accessed") + +class BadAddr(IsaFake): + ret_bad_addr = Param.Bool(True, "Return pkt status bad address on access") + + diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py index 7ac4dd701..810a320be 100644 --- a/src/python/m5/objects/System.py +++ b/src/python/m5/objects/System.py @@ -15,7 +15,7 @@ class System(SimObject): "boot processor frequency") init_param = Param.UInt64(0, "numerical value to pass into simulator") boot_osflags = Param.String("a", "boot flags to pass to the kernel") - kernel = Param.String("file that contains the kernel code") + kernel = Param.String("", "file that contains the kernel code") readfile = Param.String("", "file to read startup script from") symbolfile = Param.String("", "file to get the symbols from") diff --git a/src/python/m5/objects/T1000.py b/src/python/m5/objects/T1000.py index bb0d37bf8..79195d976 100644 --- a/src/python/m5/objects/T1000.py +++ b/src/python/m5/objects/T1000.py @@ -1,31 +1,82 @@ from m5.params import * from m5.proxy import * -from Device import BasicPioDevice +from Device import BasicPioDevice, IsaFake, BadAddr from Uart import Uart8250 from Platform import Platform from SimConsole import SimConsole, ConsoleListener -class IsaFake(BasicPioDevice): - type = 'IsaFake' - pio_size = Param.Addr(0x8, "Size of address range") - ret_data = Param.UInt8(0xFF, "Default data to return") - ret_bad_addr = Param.Bool(False, "Return pkt status bad address on access") - -class BadAddr(IsaFake): - ret_bad_addr = Param.Bool(True, "Return pkt status bad address on access") - class T1000(Platform): type = 'T1000' system = Param.System(Parent.any, "system") - fake_iob = IsaFake(pio_addr=0x8000000000, pio_size=0x7F00000000) + fake_clk = IsaFake(pio_addr=0x9600000000, pio_size=0x100000000, + warn_access="Accessing Clock Unit -- Unimplemented!") + + fake_membnks = IsaFake(pio_addr=0x9700000000, pio_size=16384, + ret_data64=0x0000000000000000, update_data=False, + warn_access="Accessing Memory Banks -- Unimplemented!") + + fake_iob = IsaFake(pio_addr=0x9800000000, pio_size=0x100000000, + warn_access="Accessing IOB -- Unimplemented!") + + fake_jbi = IsaFake(pio_addr=0x8000000000, pio_size=0x100000000, + warn_access="Accessing JBI -- Unimplemented!") + + fake_l2_1 = IsaFake(pio_addr=0xA900000000, pio_size=0x8, + ret_data64=0x0000000000000001, update_data=True, + warn_access="Accessing L2 Cache Banks -- Unimplemented!") + + fake_l2_2 = IsaFake(pio_addr=0xA900000040, pio_size=0x8, + ret_data64=0x0000000000000001, update_data=True, + warn_access="Accessing L2 Cache Banks -- Unimplemented!") + + fake_l2_3 = IsaFake(pio_addr=0xA900000080, pio_size=0x8, + ret_data64=0x0000000000000001, update_data=True, + warn_access="Accessing L2 Cache Banks -- Unimplemented!") + + fake_l2_4 = IsaFake(pio_addr=0xA9000000C0, pio_size=0x8, + ret_data64=0x0000000000000001, update_data=True, + warn_access="Accessing L2 Cache Banks -- Unimplemented!") + + fake_l2esr_1 = IsaFake(pio_addr=0xAB00000000, pio_size=0x8, + ret_data64=0x0000000000000000, update_data=True, + warn_access="Accessing L2 ESR Cache Banks -- Unimplemented!") + + fake_l2esr_2 = IsaFake(pio_addr=0xAB00000040, pio_size=0x8, + ret_data64=0x0000000000000000, update_data=True, + warn_access="Accessing L2 ESR Cache Banks -- Unimplemented!") + + fake_l2esr_3 = IsaFake(pio_addr=0xAB00000080, pio_size=0x8, + ret_data64=0x0000000000000000, update_data=True, + warn_access="Accessing L2 ESR Cache Banks -- Unimplemented!") + + fake_l2esr_4 = IsaFake(pio_addr=0xAB000000C0, pio_size=0x8, + ret_data64=0x0000000000000000, update_data=True, + warn_access="Accessing L2 ESR Cache Banks -- Unimplemented!") + + fake_ssi = IsaFake(pio_addr=0xff00000000, pio_size=0x10000000, + warn_access="Accessing SSI -- Unimplemented!") - uart = Uart8250(pio_addr=0xfff0c2c000) + hvuart = Uart8250(pio_addr=0xfff0c2c000) + puart0 = Uart8250(pio_addr=0x1f10000000) console = SimConsole(listener = ConsoleListener()) # Attach I/O devices to specified bus object. Can't do this # earlier, since the bus object itself is typically defined at the # System level. def attachIO(self, bus): + self.fake_clk.pio = bus.port + self.fake_membnks.pio = bus.port self.fake_iob.pio = bus.port - self.uart.pio = bus.port + self.fake_jbi.pio = bus.port + self.fake_l2_1.pio = bus.port + self.fake_l2_2.pio = bus.port + self.fake_l2_3.pio = bus.port + self.fake_l2_4.pio = bus.port + self.fake_l2esr_1.pio = bus.port + self.fake_l2esr_2.pio = bus.port + self.fake_l2esr_3.pio = bus.port + self.fake_l2esr_4.pio = bus.port + self.fake_ssi.pio = bus.port + self.puart0.pio = bus.port + self.hvuart.pio = bus.port diff --git a/src/python/m5/objects/Tsunami.py b/src/python/m5/objects/Tsunami.py index ffe93727b..ac9020b47 100644 --- a/src/python/m5/objects/Tsunami.py +++ b/src/python/m5/objects/Tsunami.py @@ -1,6 +1,6 @@ from m5.params import * from m5.proxy import * -from Device import BasicPioDevice +from Device import BasicPioDevice, IsaFake, BadAddr from Platform import Platform from AlphaConsole import AlphaConsole from Uart import Uart8250 @@ -11,15 +11,6 @@ class TsunamiCChip(BasicPioDevice): type = 'TsunamiCChip' tsunami = Param.Tsunami(Parent.any, "Tsunami") -class IsaFake(BasicPioDevice): - type = 'IsaFake' - pio_size = Param.Addr(0x8, "Size of address range") - ret_data = Param.UInt8(0xFF, "Default data to return") - ret_bad_addr = Param.Bool(False, "Return pkt status bad address on access") - -class BadAddr(IsaFake): - ret_bad_addr = Param.Bool(True, "Return pkt status bad address on access") - class TsunamiIO(BasicPioDevice): type = 'TsunamiIO' time = Param.UInt64(1136073600, @@ -45,7 +36,7 @@ class Tsunami(Platform): fake_uart3 = IsaFake(pio_addr=0x801fc0002e8) fake_uart4 = IsaFake(pio_addr=0x801fc0003f0) - fake_ppc = IsaFake(pio_addr=0x801fc0003bc) + fake_ppc = IsaFake(pio_addr=0x801fc0003bb) fake_OROM = IsaFake(pio_addr=0x800000a0000, pio_size=0x60000) diff --git a/src/sim/host.hh b/src/sim/host.hh index a2faa206b..8b1ddbfe7 100644 --- a/src/sim/host.hh +++ b/src/sim/host.hh @@ -42,7 +42,7 @@ /** uint64_t constant */ #define ULL(N) ((uint64_t)N##ULL) /** int64_t constant */ -#define LL(N) (((int64_t)N##LL) +#define LL(N) ((int64_t)N##LL) /** Statistics counter type. Not much excuse for not using a 64-bit * integer here, but if you're desperate and only run short diff --git a/src/sim/system.cc b/src/sim/system.cc index 4b42d41fc..b3ba1b8f1 100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -89,36 +89,41 @@ System::System(Params *p) /** * Load the kernel code into memory */ - // Load kernel code - kernel = createObjectFile(params()->kernel_path); - if (kernel == NULL) - fatal("Could not load kernel file %s", params()->kernel_path); - - // Load program sections into memory - kernel->loadSections(&functionalPort, LoadAddrMask); - - // setup entry points - kernelStart = kernel->textBase(); - kernelEnd = kernel->bssBase() + kernel->bssSize(); - kernelEntry = kernel->entryPoint(); - - // load symbols - if (!kernel->loadGlobalSymbols(kernelSymtab)) - panic("could not load kernel symbols\n"); - - if (!kernel->loadLocalSymbols(kernelSymtab)) - panic("could not load kernel local symbols\n"); - - if (!kernel->loadGlobalSymbols(debugSymbolTable)) - panic("could not load kernel symbols\n"); - - if (!kernel->loadLocalSymbols(debugSymbolTable)) - panic("could not load kernel local symbols\n"); - - DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); - DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); - DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); - DPRINTF(Loader, "Kernel loaded...\n"); + if (params()->kernel_path == "") { + warn("No kernel set for full system simulation. Assuming you know what" + " you're doing...\n"); + } else { + // Load kernel code + kernel = createObjectFile(params()->kernel_path); + if (kernel == NULL) + fatal("Could not load kernel file %s", params()->kernel_path); + + // Load program sections into memory + kernel->loadSections(&functionalPort, LoadAddrMask); + + // setup entry points + kernelStart = kernel->textBase(); + kernelEnd = kernel->bssBase() + kernel->bssSize(); + kernelEntry = kernel->entryPoint(); + + // load symbols + if (!kernel->loadGlobalSymbols(kernelSymtab)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(kernelSymtab)) + panic("could not load kernel local symbols\n"); + + if (!kernel->loadGlobalSymbols(debugSymbolTable)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(debugSymbolTable)) + panic("could not load kernel local symbols\n"); + + DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); + DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); + DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); + DPRINTF(Loader, "Kernel loaded...\n"); + } #endif // FULL_SYSTEM // increment the number of running systms diff --git a/src/unittest/rangemaptest.cc b/src/unittest/rangemaptest.cc new file mode 100644 index 000000000..983a41520 --- /dev/null +++ b/src/unittest/rangemaptest.cc @@ -0,0 +1,74 @@ +/* + * 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 <iostream> +#include <cassert> +#include "sim/host.hh" +#include "base/range_map.hh" + +using namespace std; + +int main() +{ + range_map<Addr,int> r; + + range_map<Addr,int>::iterator i; + + i = r.insert(RangeIn<Addr>(10,40),5); + assert(i != r.end()); + i = r.insert(RangeIn<Addr>(60,90),3); + assert(i != r.end()); + + i = r.find(RangeIn(20,30)); + assert(i != r.end()); + cout << i->first << " " << i->second << endl; + + i = r.find(RangeIn(55,55)); + assert(i == r.end()); + + i = r.insert(RangeIn<Addr>(0,12),1); + assert(i == r.end()); + + i = r.insert(RangeIn<Addr>(0,9),1); + assert(i != r.end()); + + i = r.find(RangeIn(20,30)); + assert(i != r.end()); + cout << i->first << " " << i->second << endl; + +} + + + + + + + + diff --git a/src/unittest/rangemaptest2.cc b/src/unittest/rangemaptest2.cc new file mode 100644 index 000000000..b253dbe86 --- /dev/null +++ b/src/unittest/rangemaptest2.cc @@ -0,0 +1,78 @@ +/* + * 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 <iostream> +#include <cassert> +#include "sim/host.hh" +#include "base/range_map.hh" + +using namespace std; + +int main() +{ + range_multimap<Addr,int> r; + + range_multimap<Addr,int>::iterator i; + std::pair<range_multimap<Addr,int>::iterator,range_multimap<Addr,int>::iterator> + jk; + + i = r.insert(RangeIn<Addr>(10,40),5); + assert(i != r.end()); + i = r.insert(RangeIn<Addr>(10,40),6); + assert(i != r.end()); + i = r.insert(RangeIn<Addr>(60,90),3); + assert(i != r.end()); + + jk = r.find(RangeIn(20,30)); + assert(jk.first != r.end()); + cout << jk.first->first << " " << jk.first->second << endl; + cout << jk.second->first << " " << jk.second->second << endl; + + i = r.insert(RangeIn<Addr>(0,3),5); + assert(i != r.end()); + + for( i = r.begin(); i != r.end(); i++) + cout << i->first << " " << i->second << endl; + + jk = r.find(RangeIn(20,30)); + assert(jk.first != r.end()); + cout << jk.first->first << " " << jk.first->second << endl; + cout << jk.second->first << " " << jk.second->second << endl; + + +} + + + + + + + + |