diff options
99 files changed, 6801 insertions, 1455 deletions
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 546569f30..72742775f 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -84,17 +84,30 @@ def makeSparcSystem(mem_mode, mdesc = None): # generic system mdesc = SysConfig() self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) self.membus = Bus(bus_id=1) - self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self.bridge = Bridge() + self.t1000 = T1000() + self.t1000.attachIO(self.iobus) + 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') self.openboot_bin = binary('openboot.bin') + self.nvram_bin = binary('nvram1') + self.hypervisor_desc_bin = binary('1up-hv.bin') + self.partition_desc_bin = binary('1up-md.bin') return self 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/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 a96622d4a..59eb18c9c 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -1307,7 +1307,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->readMiscReg(%s)' % self.reg_spec + base = 'xc->readMiscRegWithEffect(%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 4cf411d3b..64cfc832a 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -284,6 +284,11 @@ void enterREDState(ThreadContext *tc) //HPSTATE.hpriv = 1 HPSTATE |= (1 << 2); tc->setMiscRegWithEffect(MISCREG_HPSTATE, HPSTATE); + //PSTATE.priv is set to 1 here. The manual says it should be 0, but + //Legion sets it to 1. + MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE); + PSTATE |= (1 << 2); + tc->setMiscRegWithEffect(MISCREG_PSTATE, PSTATE); } /** @@ -340,10 +345,12 @@ void doREDFault(ThreadContext *tc, TrapType tt) PSTATE |= (1 << 4); //set PSTATE.am to 0 PSTATE &= ~(1 << 3); - //set PSTATE.priv to 0 - PSTATE &= ~(1 << 2); +/* //set PSTATE.priv to 0 + PSTATE &= ~(1 << 2);*/ //set PSTATE.ie to 0 - PSTATE &= ~(1 << 1); + //PSTATE.priv is set to 1 here. The manual says it should be 0, but + //Legion sets it to 1. + PSTATE |= (1 << 2); //set PSTATE.cle to 0 PSTATE &= ~(1 << 9); //PSTATE.tle is unchanged @@ -451,7 +458,9 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) else { //PSTATE.priv = 0 - PSTATE &= ~(1 << 2); + //PSTATE.priv is set to 1 here. The manual says it should be 0, but + //Legion sets it to 1. + PSTATE |= (1 << 2); //PSTATE.cle = 0 PSTATE &= ~(1 << 9); } @@ -519,7 +528,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()++; @@ -533,40 +542,35 @@ void SparcFaultBase::invoke(ThreadContext * tc) Addr PC, NPC; PrivilegeLevel current; - if(!(PSTATE & (1 << 2))) - current = User; - else if(!(HPSTATE & (1 << 2))) + if(HPSTATE & (1 << 2)) + current = Hyperprivileged; + else if(PSTATE & (1 << 2)) current = Privileged; else - current = Hyperprivileged; + current = User; PrivilegeLevel level = getNextLevel(current); - if(HPSTATE & (1 << 5) || TL == MaxTL - 1) - { + if(HPSTATE & (1 << 5) || TL == MaxTL - 1) { getREDVector(5, PC, NPC); - enterREDState(tc); doREDFault(tc, TT); - } - else if(TL == MaxTL) - { + //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) { + 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); } @@ -578,9 +582,6 @@ void SparcFaultBase::invoke(ThreadContext * tc) void PowerOnReset::invoke(ThreadContext * tc) { - //First, enter RED state. - enterREDState(tc); - //For SPARC, when a system is first started, there is a power //on reset Trap which sets the processor into the following state. //Bits that aren't set aren't defined on startup. @@ -589,15 +590,28 @@ void PowerOnReset::invoke(ThreadContext * tc) tc->setMiscReg(MISCREG_TT, trapType()); tc->setMiscRegWithEffect(MISCREG_GL, MaxGL); - //Turn on pef, set everything else to 0 - tc->setMiscReg(MISCREG_PSTATE, 1 << 4); + //Turn on pef and priv, set everything else to 0 + tc->setMiscReg(MISCREG_PSTATE, (1 << 4) | (1 << 2)); //Turn on red and hpriv, set everything else to 0 - tc->setMiscReg(MISCREG_HPSTATE, (1 << 5) | (1 << 2)); + MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); + //HPSTATE.red = 1 + HPSTATE |= (1 << 5); + //HPSTATE.hpriv = 1 + HPSTATE |= (1 << 2); + //HPSTATE.ibe = 0 + HPSTATE &= ~(1 << 10); + //HPSTATE.tlz = 0 + HPSTATE &= ~(1 << 0); + tc->setMiscReg(MISCREG_HPSTATE, HPSTATE); //The tick register is unreadable by nonprivileged software tc->setMiscReg(MISCREG_TICK, 1ULL << 63); + //Enter RED state. We do this last so that the actual state preserved in + //the trap stack is the state from before this fault. + enterREDState(tc); + Addr PC, NPC; getREDVector(trapType(), PC, NPC); tc->setPC(PC); diff --git a/src/arch/sparc/floatregfile.hh b/src/arch/sparc/floatregfile.hh index 9d760c9ff..72803a5e0 100644 --- a/src/arch/sparc/floatregfile.hh +++ b/src/arch/sparc/floatregfile.hh @@ -38,10 +38,15 @@ #include <string> +class Checkpoint; + namespace SparcISA { std::string getFloatRegName(RegIndex); + const int NumFloatArchRegs = 64; + const int NumFloatRegs = 64; + typedef float float32_t; typedef double float64_t; //FIXME long double refers to a 10 byte float, rather than a 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.cc b/src/arch/sparc/intregfile.cc index 358368e5f..0a8ac055f 100644 --- a/src/arch/sparc/intregfile.cc +++ b/src/arch/sparc/intregfile.cc @@ -31,6 +31,7 @@ #include "arch/sparc/intregfile.hh" #include "base/trace.hh" +#include "base/misc.hh" #include "sim/serialize.hh" #include <string.h> @@ -42,7 +43,7 @@ class Checkpoint; string SparcISA::getIntRegName(RegIndex index) { - static std::string intRegName[NumIntRegs] = + static std::string intRegName[NumIntArchRegs] = {"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", @@ -78,30 +79,30 @@ IntRegFile::IntRegFile() IntReg IntRegFile::readReg(int intReg) { IntReg val; - if(intReg < NumRegularIntRegs) + if(intReg < NumIntArchRegs) val = regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask]; - else if((intReg -= NumRegularIntRegs) < NumMicroIntRegs) + else if((intReg -= NumIntArchRegs) < NumMicroIntRegs) val = microRegs[intReg]; else - panic("Tried to read non-existant integer register %d, %d\n", NumRegularIntRegs + NumMicroIntRegs + intReg, intReg); + panic("Tried to read non-existant integer register %d, %d\n", + NumIntArchRegs + NumMicroIntRegs + intReg, intReg); DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val); return val; } -Fault IntRegFile::setReg(int intReg, const IntReg &val) +void IntRegFile::setReg(int intReg, const IntReg &val) { if(intReg) { DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); - if(intReg < NumRegularIntRegs) + if(intReg < NumIntArchRegs) regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val; - else if((intReg -= NumRegularIntRegs) < NumMicroIntRegs) + else if((intReg -= NumIntArchRegs) < NumMicroIntRegs) microRegs[intReg] = val; else panic("Tried to set non-existant integer register\n"); } - return NoFault; } //This doesn't effect the actual CWP register. diff --git a/src/arch/sparc/intregfile.hh b/src/arch/sparc/intregfile.hh index 223e3b34c..d66d0fcb7 100644 --- a/src/arch/sparc/intregfile.hh +++ b/src/arch/sparc/intregfile.hh @@ -32,12 +32,13 @@ #ifndef __ARCH_SPARC_INTREGFILE_HH__ #define __ARCH_SPARC_INTREGFILE_HH__ -#include "arch/sparc/faults.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/types.hh" #include <string> +class Checkpoint; + namespace SparcISA { class RegFile; @@ -45,6 +46,9 @@ namespace SparcISA //This function translates integer register file indices into names std::string getIntRegName(RegIndex); + const int NumIntArchRegs = 32; + const int NumIntRegs = MaxGL * 8 + NWindows * 16 + NumMicroIntRegs; + class IntRegFile { private: @@ -63,7 +67,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]; @@ -85,7 +89,7 @@ namespace SparcISA IntReg readReg(int intReg); - Fault setReg(int intReg, const IntReg &val); + void setReg(int intReg, const IntReg &val); void serialize(std::ostream &os); diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa index aa24c75be..4a806bfd0 100644 --- a/src/arch/sparc/isa/base.isa +++ b/src/arch/sparc/isa/base.isa @@ -205,7 +205,7 @@ output decoder {{ else if(reg < MaxMicroReg) ccprintf(os, "%%u%d", reg - MaxInput); else { - ccprintf(os, "%%f%d", reg - FP_Base_DepTag); + ccprintf(os, "%%f%d", reg - MaxMicroReg); } } diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 2c8e59a1d..7a48042c2 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -307,7 +307,7 @@ decode OP default Unknown::unknown() int64_t resTemp, val2 = Rs2_or_imm13; Rd = resTemp = Rs1 + val2; int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{((Rs1<31:0> + val2<31:0>)<32:0>)}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} @@ -316,7 +316,7 @@ decode OP default Unknown::unknown() int64_t resTemp, val2 = Rs2_or_imm13; Rd = resTemp = Rs1 + val2; int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31}}, + {{(Rs1<31:0> + val2<31:0>)<32:0>}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} @@ -327,7 +327,7 @@ decode OP default Unknown::unknown() int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != Rd<31:>); if(overflow) fault = new TagOverflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{((Rs1<31:0> + val2<31:0>)<32:0>)}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != Rd<63:>}} @@ -337,7 +337,7 @@ decode OP default Unknown::unknown() Rd = resTemp = Rs1 + val2; int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); if(overflow) fault = new TagOverflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{((Rs1<31:0> + val2<31:0>)<32:0>)}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} @@ -347,13 +347,12 @@ decode OP default Unknown::unknown() int32_t multiplier = Rs1<31:0>; int32_t savedLSB = Rs1<0:>; multiplier = multiplier<31:1> | - ((Ccr<3:3> - ^ Ccr<1:1>) << 32); + ((Ccr<3:3> ^ Ccr<1:1>) << 32); if(!Y<0:>) multiplicand = 0; Rd = resTemp = multiplicand + multiplier; Y = Y<31:1> | (savedLSB << 31);}}, - {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}}, + {{((multiplicand<31:0> + multiplier<31:0>)<32:0>)}}, {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}}, {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}}, {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}} @@ -527,7 +526,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 @@ -1005,6 +1004,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; @@ -1017,6 +1017,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; @@ -1055,36 +1056,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 { @@ -1101,7 +1102,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 { @@ -1153,7 +1154,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 @@ -1236,7 +1237,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 @@ -1273,7 +1274,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;}}, @@ -1281,7 +1282,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 cb6c2f161..55e9fba45 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', code, @@ -62,25 +62,26 @@ let {{ header_output = MemDeclare.subst(iop) + MemDeclare.subst(iop_imm) decoder_output = BasicConstructor.subst(iop) + BasicConstructor.subst(iop_imm) decode_block = ROrImmDecode.subst(iop) - exec_output = doDualSplitExecute(code, addrCalcReg, addrCalcImm, execute, - faultCode, name, name + "Imm", Name, Name + "Imm", opt_flags) + exec_output = doDualSplitExecute(code, addrCalcReg, addrCalcImm, + execute, faultCode, name, name + "Imm", Name, Name + "Imm", + asi, opt_flags) 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, LoadExecute, - 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, StoreExecute, - AlternateAsiPrivFaultCheck, name, Name, opt_flags) + AlternateASIPrivFaultCheck, name, Name, asi, opt_flags) }}; def format Load(code, *opt_flags) {{ @@ -88,7 +89,7 @@ def format Load(code, *opt_flags) {{ decoder_output, exec_output, decode_block) = doMemFormat(code, - LoadExecute, '', name, Name, opt_flags) + LoadExecute, '', name, Name, 0, opt_flags) }}; def format Store(code, *opt_flags) {{ @@ -96,5 +97,5 @@ def format Store(code, *opt_flags) {{ decoder_output, exec_output, decode_block) = doMemFormat(code, - StoreExecute, '', name, Name, opt_flags) + StoreExecute, '', 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 8b4aca473..7a1a58d13 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,12 +309,12 @@ 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) {{ +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. @@ -323,10 +323,10 @@ def format BlockLoad(code, *opt_flags) {{ decoder_output, exec_output, decode_block) = doBlockMemFormat(code, faultCode, - LoadExecute, name, Name, opt_flags) + LoadExecute, name, Name, asi, opt_flags) }}; -def format BlockStore(code, *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. @@ -335,5 +335,5 @@ def format BlockStore(code, *opt_flags) {{ decoder_output, exec_output, decode_block) = doBlockMemFormat(code, faultCode, - StoreExecute, name, Name, opt_flags) + StoreExecute, 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 b9f7fde2d..3e9fd7a7d 100644 --- a/src/arch/sparc/isa/formats/mem/util.isa +++ b/src/arch/sparc/isa/formats/mem/util.isa @@ -76,19 +76,22 @@ output decoder {{ { std::stringstream response; bool load = flags[IsLoad]; - bool save = flags[IsStore]; + bool store = flags[IsStore]; printMnemonic(response, mnemonic); - if(save) + if(store) { printReg(response, _srcRegIdx[0]); ccprintf(response, ", "); } - ccprintf(response, "[ "); - printReg(response, _srcRegIdx[!save ? 0 : 1]); - ccprintf(response, " + "); - printReg(response, _srcRegIdx[!save ? 1 : 2]); - ccprintf(response, " ]"); + ccprintf(response, "["); + if(_srcRegIdx[!store ? 0 : 1] != 0) + { + printSrcReg(response, !store ? 0 : 1); + ccprintf(response, " + "); + } + printSrcReg(response, !store ? 1 : 2); + ccprintf(response, "]"); if(load) { ccprintf(response, ", "); @@ -111,12 +114,16 @@ output decoder {{ printReg(response, _srcRegIdx[0]); ccprintf(response, ", "); } - ccprintf(response, "[ "); - printReg(response, _srcRegIdx[!save ? 0 : 1]); + ccprintf(response, "["); + if(_srcRegIdx[!save ? 0 : 1] != 0) + { + printReg(response, _srcRegIdx[!save ? 0 : 1]); + ccprintf(response, " + "); + } if(imm >= 0) - ccprintf(response, " + 0x%x ]", imm); + ccprintf(response, "0x%x]", imm); else - ccprintf(response, " + -0x%x ]", -imm); + ccprintf(response, "-0x%x]", -imm); if(load) { ccprintf(response, ", "); @@ -141,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) { @@ -149,8 +156,8 @@ def template LoadExecute {{ } if(fault == NoFault) { - //Write the resulting state to the execution context - %(op_wb)s; + //Write the resulting state to the execution context + %(op_wb)s; } return fault; @@ -168,7 +175,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); } return fault; } @@ -195,7 +202,6 @@ def template StoreExecute {{ Trace::InstRecord *traceData) const { Fault fault = NoFault; - uint64_t write_result = 0; //This is to support the conditional store in cas instructions. //It should be optomized out in all the others bool storeCond = true; @@ -211,12 +217,13 @@ def template StoreExecute {{ } if(storeCond && fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, &write_result); + fault = xc->write((uint%(mem_acc_size)s_t)Mem, + EA, %(asi_val)s, 0); } if(fault == NoFault) { - //Write the resulting state to the execution context - %(op_wb)s; + //Write the resulting state to the execution context + %(op_wb)s; } return fault; @@ -226,7 +233,6 @@ def template StoreExecute {{ Trace::InstRecord * traceData) const { Fault fault = NoFault; - uint64_t write_result = 0; bool storeCond = true; Addr EA; %(op_decl)s; @@ -240,11 +246,12 @@ def template StoreExecute {{ } if(storeCond && fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, &write_result); + fault = xc->write((uint%(mem_acc_size)s_t)Mem, + EA, %(asi_val)s, 0); } if(fault == NoFault) { - //Write the resulting state to the execution context + //Write the resulting state to the execution context %(op_wb)s; } return fault; @@ -281,8 +288,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; ''' @@ -293,7 +301,7 @@ let {{ //instruction at a certain micropc let {{ def makeMicroName(name, microPc): - return name + "::" + name + "_" + str(microPc) + return name + "::" + name + "_" + str(microPc) }}; //This function properly generates the execute functions for one of the @@ -302,13 +310,14 @@ 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(code, eaCode, execute, - faultCode, name, Name, opt_flags): - codeIop = InstObjParams(name, Name, '', code, opt_flags) - eaIop = InstObjParams(name, Name, '', eaCode, - opt_flags, {"fault_check": faultCode}) - iop = InstObjParams(name, Name, '', code, opt_flags, - {"fault_check": faultCode, "ea_code" : eaCode}) + def doSplitExecute(code, execute, name, Name, asi, opt_flags, microParam): + microParam["asi_val"] = asi; + codeParam = microParam.copy() + codeParam["ea_code"] = '' + codeIop = InstObjParams(name, Name, '', code, opt_flags, codeParam) + eaIop = InstObjParams(name, Name, '', microParam["ea_code"], + opt_flags, microParam) + iop = InstObjParams(name, Name, '', code, opt_flags, microParam) (iop.ea_decl, iop.ea_rd, iop.ea_wb) = (eaIop.op_decl, eaIop.op_rd, eaIop.op_wb) @@ -319,12 +328,13 @@ let {{ 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), (eaImmCode, nameImm, NameImm)): - executeCode += doSplitExecute(code, eaCode, - execute, faultCode, name, Name, opt_flags) + microParams = {"ea_code" : eaCode, "fault_check": faultCode} + executeCode += doSplitExecute(code, execute, name, Name, + asi, opt_flags, microParams) return executeCode }}; diff --git a/src/arch/sparc/isa/formats/priv.isa b/src/arch/sparc/isa/formats/priv.isa index 94a68aebe..3d47ca02f 100644 --- a/src/arch/sparc/isa/formats/priv.isa +++ b/src/arch/sparc/isa/formats/priv.isa @@ -153,8 +153,13 @@ output decoder {{ printMnemonic(response, mnemonic); ccprintf(response, " "); - printSrcReg(response, 0); - ccprintf(response, ", "); + //If the first reg is %g0, don't print it. + //This improves readability + if(_srcRegIdx[0] != 0) + { + printSrcReg(response, 0); + ccprintf(response, ", "); + } printSrcReg(response, 1); ccprintf(response, ", %%%s", regName); @@ -169,8 +174,14 @@ output decoder {{ printMnemonic(response, mnemonic); ccprintf(response, " "); - printSrcReg(response, 0); - ccprintf(response, ", 0x%x, %%%s", imm, regName); + //If the first reg is %g0, don't print it. + //This improves readability + if(_srcRegIdx[0] != 0) + { + printSrcReg(response, 0); + ccprintf(response, ", "); + } + ccprintf(response, "0x%x, %%%s", imm, regName); return response.str(); } diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa index 2d200f568..80ed7362c 100644 --- a/src/arch/sparc/isa/operands.isa +++ b/src/arch/sparc/isa/operands.isa @@ -61,7 +61,7 @@ def operands {{ 'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 3), 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 4), 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 5), - 'uReg0': ('IntReg', 'udw', 'NumRegularIntRegs+0', 'IsInteger', 6), + 'uReg0': ('IntReg', 'udw', 'NumIntArchRegs', 'IsInteger', 6), 'Frds': ('FloatReg', 'sf', 'RD', 'IsFloating', 10), 'Frd': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10), # Each Frd_N refers to the Nth double precision register from Frd. diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh index 1433ba3f8..3f0b9cad5 100644 --- a/src/arch/sparc/isa_traits.hh +++ b/src/arch/sparc/isa_traits.hh @@ -26,34 +26,27 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black + * Ali Saidi */ #ifndef __ARCH_SPARC_ISA_TRAITS_HH__ #define __ARCH_SPARC_ISA_TRAITS_HH__ #include "arch/sparc/types.hh" -#include "base/misc.hh" +#include "arch/sparc/sparc_traits.hh" #include "config/full_system.hh" #include "sim/host.hh" -class ThreadContext; -class FastCPU; -//class FullCPU; -class Checkpoint; - -class StaticInst; 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; @@ -63,32 +56,12 @@ namespace SparcISA // SPARC NOP (sethi %(hi(0), g0) const MachInst NoopMachInst = 0x01000000; - const int NumRegularIntRegs = 32; - const int NumMicroIntRegs = 1; - const int NumIntRegs = - NumRegularIntRegs + - NumMicroIntRegs; - const int NumFloatRegs = 64; - const int NumMiscRegs = 40; - // These enumerate all the registers for dependence tracking. enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..95 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = NumIntRegs, - Ctrl_Base_DepTag = NumIntRegs + NumMicroIntRegs + NumFloatRegs, + FP_Base_DepTag = 33, + Ctrl_Base_DepTag = 97, }; - - // MAXTL - maximum trap level - const int MaxPTL = 2; - const int MaxTL = 6; - const int MaxGL = 3; - const int MaxPGL = 2; - - // NWINDOWS - number of register windows, can be 3 to 32 - const int NWindows = 8; - // semantically meaningful register indices const int ZeroReg = 0; // architecturally meaningful // the rest of these depend on the ABI @@ -116,23 +89,35 @@ namespace SparcISA //Why does both the previous set of constants and this one exist? const int PageShift = 13; - const int PageBytes = ULL(1) << PageShift; + const int PageBytes = 1ULL << PageShift; const int BranchPredAddrShiftAmt = 2; - const int MachineBytes = 8; - const int WordBytes = 4; - const int HalfwordBytes = 2; - const int ByteBytes = 1; + StaticInstPtr decodeInst(ExtMachInst); + +#if FULL_SYSTEM + ////////// Interrupt Stuff /////////// + enum InterruptLevels + { + INTLEVEL_MIN = 1, + INTLEVEL_MAX = 15, - void serialize(std::ostream & os); + NumInterruptLevels = INTLEVEL_MAX - INTLEVEL_MIN + }; - void unserialize(Checkpoint *cp, const std::string §ion); + // 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); - StaticInstPtr decodeInst(ExtMachInst); + /////////// 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); - // return a no-op instruction... used for instruction fetch faults - extern const MachInst NoopMachInst; +#endif } #endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc index d52e3983f..53559c072 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; @@ -50,24 +46,29 @@ class Checkpoint; string SparcISA::getMiscRegName(RegIndex index) { static::string miscRegName[NumMiscRegs] = - {"y", "ccr", "asi", "tick", "pc", "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"}; + {"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]; } -void MiscRegFile::reset() +enum RegMask +{ + PSTATE_MASK = (((1 << 4) - 1) << 1) | (((1 << 4) - 1) << 6) | (1 << 12) +}; + +void MiscRegFile::clear() { y = 0; ccr = 0; asi = 0; - tick = 0; + tick = ULL(1) << 63; fprs = 0; gsr = 0; softint = 0; @@ -88,129 +89,285 @@ void MiscRegFile::reset() otherwin = 0; wstate = 0; gl = 0; - hpstate = 0; + //In a T1, bit 11 is apparently always 1 + hpstate = (1 << 11); memset(htstate, 0, sizeof(htstate)); hintp = 0; htba = 0; hstick_cmpr = 0; - strandStatusReg = 0; + //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); } @@ -218,239 +375,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; - 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; - 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; -#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. + 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_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); @@ -483,8 +695,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) @@ -514,29 +754,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 f74943256..c879fd357 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" @@ -42,14 +41,13 @@ namespace SparcISA { - //These functions map register indices to names std::string getMiscRegName(RegIndex); enum MiscRegIndex { /** Ancillary State Registers */ - MISCREG_Y, + MISCREG_Y, /* 0 */ MISCREG_CCR, MISCREG_ASI, MISCREG_TICK, @@ -59,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, @@ -71,7 +69,7 @@ namespace SparcISA MISCREG_TT, MISCREG_PRIVTICK, MISCREG_TBA, - MISCREG_PSTATE, + MISCREG_PSTATE, /* 20 */ MISCREG_TL, MISCREG_PIL, MISCREG_CWP, @@ -83,7 +81,7 @@ namespace SparcISA MISCREG_GL, /** Hyper privileged registers */ - MISCREG_HPSTATE, + MISCREG_HPSTATE, /* 30 */ MISCREG_HTSTATE, MISCREG_HINTP, MISCREG_HTBA, @@ -92,9 +90,79 @@ namespace SparcISA MISCREG_HSTICK_CMPR, /** Floating Point Status Register */ - MISCREG_FSR + 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; + // The control registers, broken out into fields class MiscRegFile { @@ -146,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); @@ -172,11 +277,11 @@ namespace SparcISA #endif public: - void reset(); + void clear(); MiscRegFile() { - reset(); + clear(); } MiscReg readReg(int miscReg); @@ -188,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); @@ -209,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/process.cc b/src/arch/sparc/process.cc index 3efe4fc08..405e408e5 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -32,6 +32,7 @@ #include "arch/sparc/asi.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/process.hh" +#include "arch/sparc/types.hh" #include "base/loader/object_file.hh" #include "base/loader/elf_object.hh" #include "base/misc.hh" @@ -77,7 +78,7 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, void SparcLiveProcess::startup() { - argsInit(MachineBytes, VMPageSize); + argsInit(sizeof(IntReg), VMPageSize); //From the SPARC ABI diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc index 65e6017da..5d8ac6a17 100644 --- a/src/arch/sparc/regfile.cc +++ b/src/arch/sparc/regfile.cc @@ -70,8 +70,9 @@ void RegFile::setNextNPC(Addr val) void RegFile::clear() { - intRegFile.clear(); floatRegFile.clear(); + intRegFile.clear(); + miscRegFile.clear(); } MiscReg RegFile::readMiscReg(int miscReg) @@ -253,6 +254,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 9f33435f6..0a09d0f66 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/sparc_traits.hh b/src/arch/sparc/sparc_traits.hh new file mode 100644 index 000000000..a3d29ea8a --- /dev/null +++ b/src/arch/sparc/sparc_traits.hh @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003-2005 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: Gabe Black + */ + +#ifndef __ARCH_SPARC_SPARC_TRAITS_HH__ +#define __ARCH_SPARC_SPARC_TRAITS_HH__ + +namespace SparcISA +{ + // Max trap levels + const int MaxPTL = 2; + const int MaxTL = 6; + const int MaxGL = 3; + const int MaxPGL = 2; + + // Number of register windows, can legally be 3 to 32 + const int NWindows = 8; + const int NumMicroIntRegs = 1; + +// const int NumRegularIntRegs = MaxGL * 8 + NWindows * 16; +// const int NumMicroIntRegs = 1; +// const int NumIntRegs = +// NumRegularIntRegs + +// NumMicroIntRegs; +// const int NumFloatRegs = 64; +// const int NumMiscRegs = 40; +} + +#endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc index 4e907f002..da83d86fc 100644 --- a/src/arch/sparc/system.cc +++ b/src/arch/sparc/system.cc @@ -42,18 +42,35 @@ using namespace BigEndianGuest; SparcSystem::SparcSystem(Params *p) - : System(p), sysTick(0),funcRomPort(p->name + "-fport") - + : System(p), sysTick(0),funcRomPort(p->name + "-fromport"), + funcNvramPort(p->name + "-fnvramport"), + funcHypDescPort(p->name + "-fhypdescport"), + funcPartDescPort(p->name + "-fpartdescport") { resetSymtab = new SymbolTable; hypervisorSymtab = new SymbolTable; openbootSymtab = new SymbolTable; + nvramSymtab = new SymbolTable; + hypervisorDescSymtab = new SymbolTable; + partitionDescSymtab = new SymbolTable; Port *rom_port; rom_port = params()->rom->getPort("functional"); funcRomPort.setPeer(rom_port); rom_port->setPeer(&funcRomPort); + rom_port = params()->nvram->getPort("functional"); + funcNvramPort.setPeer(rom_port); + rom_port->setPeer(&funcNvramPort); + + rom_port = params()->hypervisor_desc->getPort("functional"); + funcHypDescPort.setPeer(rom_port); + rom_port->setPeer(&funcHypDescPort); + + rom_port = params()->partition_desc->getPort("functional"); + funcPartDescPort.setPeer(rom_port); + rom_port->setPeer(&funcPartDescPort); + /** * Load the boot code, and hypervisor into memory. */ @@ -72,6 +89,23 @@ SparcSystem::SparcSystem(Params *p) if (hypervisor == NULL) fatal("Could not load hypervisor binary %s", params()->hypervisor_bin); + // Read the nvram image + nvram = createObjectFile(params()->nvram_bin, true); + if (nvram == NULL) + fatal("Could not load nvram image %s", params()->nvram_bin); + + // Read the hypervisor description image + hypervisor_desc = createObjectFile(params()->hypervisor_desc_bin, true); + if (hypervisor_desc == NULL) + fatal("Could not load hypervisor description image %s", + params()->hypervisor_desc_bin); + + // Read the partition description image + partition_desc = createObjectFile(params()->partition_desc_bin, true); + if (partition_desc == NULL) + fatal("Could not load partition description image %s", + params()->partition_desc_bin); + // Load reset binary into memory reset->setTextBase(params()->reset_addr); @@ -82,6 +116,15 @@ SparcSystem::SparcSystem(Params *p) // Load the hypervisor binary hypervisor->setTextBase(params()->hypervisor_addr); hypervisor->loadSections(&funcRomPort); + // Load the nvram image + nvram->setTextBase(params()->nvram_addr); + nvram->loadSections(&funcNvramPort); + // Load the hypervisor description image + hypervisor_desc->setTextBase(params()->hypervisor_desc_addr); + hypervisor_desc->loadSections(&funcHypDescPort); + // Load the partition description image + partition_desc->setTextBase(params()->partition_desc_addr); + partition_desc->loadSections(&funcPartDescPort); // load symbols if (!reset->loadGlobalSymbols(resetSymtab)) @@ -93,6 +136,15 @@ SparcSystem::SparcSystem(Params *p) if (!hypervisor->loadLocalSymbols(hypervisorSymtab)) panic("could not load hypervisor symbols\n"); + if (!nvram->loadLocalSymbols(nvramSymtab)) + panic("could not load nvram symbols\n"); + + if (!hypervisor_desc->loadLocalSymbols(hypervisorDescSymtab)) + panic("could not load hypervisor description symbols\n"); + + if (!partition_desc->loadLocalSymbols(partitionDescSymtab)) + panic("could not load partition description symbols\n"); + // load symbols into debug table if (!reset->loadGlobalSymbols(debugSymbolTable)) panic("could not load reset symbols\n"); @@ -103,6 +155,20 @@ 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"); + + if (!hypervisor_desc->loadGlobalSymbols(debugSymbolTable)) + panic("could not load hypervisor description symbols\n"); + + if (!partition_desc->loadLocalSymbols(debugSymbolTable)) + panic("could not load partition description symbols\n"); + // @todo any fixup code over writing data in binaries on setting break // events on functions should happen here. @@ -114,9 +180,15 @@ SparcSystem::~SparcSystem() delete resetSymtab; delete hypervisorSymtab; delete openbootSymtab; + delete nvramSymtab; + delete hypervisorDescSymtab; + delete partitionDescSymtab; delete reset; delete openboot; delete hypervisor; + delete nvram; + delete hypervisor_desc; + delete partition_desc; } bool @@ -132,6 +204,9 @@ SparcSystem::serialize(std::ostream &os) resetSymtab->serialize("reset_symtab", os); hypervisorSymtab->serialize("hypervisor_symtab", os); openbootSymtab->serialize("openboot_symtab", os); + nvramSymtab->serialize("nvram_symtab", os); + hypervisorDescSymtab->serialize("hypervisor_desc_symtab", os); + partitionDescSymtab->serialize("partition_desc_symtab", os); } @@ -142,6 +217,9 @@ SparcSystem::unserialize(Checkpoint *cp, const std::string §ion) resetSymtab->unserialize("reset_symtab", cp, section); hypervisorSymtab->unserialize("hypervisor_symtab", cp, section); openbootSymtab->unserialize("openboot_symtab", cp, section); + nvramSymtab->unserialize("nvram_symtab", cp, section); + hypervisorDescSymtab->unserialize("hypervisor_desc_symtab", cp, section); + partitionDescSymtab->unserialize("partition_desc_symtab", cp, section); } @@ -149,16 +227,25 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) SimObjectParam<PhysicalMemory *> physmem; SimObjectParam<PhysicalMemory *> rom; + SimObjectParam<PhysicalMemory *> nvram; + SimObjectParam<PhysicalMemory *> hypervisor_desc; + SimObjectParam<PhysicalMemory *> partition_desc; SimpleEnumParam<System::MemoryMode> mem_mode; Param<Addr> reset_addr; Param<Addr> hypervisor_addr; Param<Addr> openboot_addr; + Param<Addr> nvram_addr; + Param<Addr> hypervisor_desc_addr; + Param<Addr> partition_desc_addr; Param<std::string> kernel; Param<std::string> reset_bin; Param<std::string> hypervisor_bin; Param<std::string> openboot_bin; + Param<std::string> nvram_bin; + Param<std::string> hypervisor_desc_bin; + Param<std::string> partition_desc_bin; Param<Tick> boot_cpu_frequency; Param<std::string> boot_osflags; @@ -171,17 +258,30 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem) INIT_PARAM(physmem, "phsyical memory"), INIT_PARAM(rom, "ROM for boot code"), + INIT_PARAM(nvram, "Non-volatile RAM for the nvram"), + INIT_PARAM(hypervisor_desc, "ROM for the hypervisor description"), + INIT_PARAM(partition_desc, "ROM for the partition description"), INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", System::MemoryModeStrings), INIT_PARAM(reset_addr, "Address that reset should be loaded at"), INIT_PARAM(hypervisor_addr, "Address that hypervisor should be loaded at"), INIT_PARAM(openboot_addr, "Address that openboot should be loaded at"), + INIT_PARAM(nvram_addr, "Address that nvram should be loaded at"), + INIT_PARAM(hypervisor_desc_addr, + "Address that hypervisor description should be loaded at"), + INIT_PARAM(partition_desc_addr, + "Address that partition description should be loaded at"), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(reset_bin, "file that contains the reset code"), INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"), INIT_PARAM(openboot_bin, "file that contains the openboot code"), + INIT_PARAM(nvram_bin, "file that contains the nvram image"), + INIT_PARAM(hypervisor_desc_bin, + "file that contains the hypervisor description image"), + INIT_PARAM(partition_desc_bin, + "file that contains the partition description image"), INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", "a"), @@ -197,14 +297,23 @@ CREATE_SIM_OBJECT(SparcSystem) p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; p->rom = rom; + p->nvram = nvram; + p->hypervisor_desc = hypervisor_desc; + p->partition_desc = partition_desc; p->mem_mode = mem_mode; p->kernel_path = kernel; p->reset_addr = reset_addr; p->hypervisor_addr = hypervisor_addr; p->openboot_addr = openboot_addr; + p->nvram_addr = nvram_addr; + p->hypervisor_desc_addr = hypervisor_desc_addr; + p->partition_desc_addr = partition_desc_addr; p->reset_bin = reset_bin; p->hypervisor_bin = hypervisor_bin; p->openboot_bin = openboot_bin; + p->nvram_bin = nvram_bin; + p->hypervisor_desc_bin = hypervisor_desc_bin; + p->partition_desc_bin = partition_desc_bin; p->boot_osflags = boot_osflags; p->init_param = init_param; p->readfile = readfile; diff --git a/src/arch/sparc/system.hh b/src/arch/sparc/system.hh index 9cf3bb568..5d50ea067 100644 --- a/src/arch/sparc/system.hh +++ b/src/arch/sparc/system.hh @@ -46,12 +46,21 @@ class SparcSystem : public System struct Params : public System::Params { PhysicalMemory *rom; + PhysicalMemory *nvram; + PhysicalMemory *hypervisor_desc; + PhysicalMemory *partition_desc; Addr reset_addr; Addr hypervisor_addr; Addr openboot_addr; + Addr nvram_addr; + Addr hypervisor_desc_addr; + Addr partition_desc_addr; std::string reset_bin; std::string hypervisor_bin; std::string openboot_bin; + std::string nvram_bin; + std::string hypervisor_desc_bin; + std::string partition_desc_bin; std::string boot_osflags; }; @@ -77,6 +86,15 @@ class SparcSystem : public System /** openboot symbol table */ SymbolTable *openbootSymtab; + /** nvram symbol table? */ + SymbolTable *nvramSymtab; + + /** hypervisor desc symbol table? */ + SymbolTable *hypervisorDescSymtab; + + /** partition desc symbol table? */ + SymbolTable *partitionDescSymtab; + /** Object pointer for the reset binary */ ObjectFile *reset; @@ -86,12 +104,30 @@ class SparcSystem : public System /** Object pointer for the openboot code */ ObjectFile *openboot; + /** Object pointer for the nvram image */ + ObjectFile *nvram; + + /** Object pointer for the hypervisor description image */ + ObjectFile *hypervisor_desc; + + /** Object pointer for the partition description image */ + ObjectFile *partition_desc; + /** System Tick for syncronized tick across all cpus. */ Tick sysTick; /** functional port to ROM */ FunctionalPort funcRomPort; + /** functional port to nvram */ + FunctionalPort funcNvramPort; + + /** functional port to hypervisor description */ + FunctionalPort funcHypDescPort; + + /** functional port to partition description */ + FunctionalPort funcPartDescPort; + protected: const Params *params() const { return (const Params *)_params; } 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 113f0fe74..3fe40b4c1 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; } @@ -66,6 +70,56 @@ SharedData *shared_data = NULL; // Methods for the InstRecord object // +#if THE_ISA == SPARC_ISA + +inline char * genCenteredLabel(int length, char * buffer, char * label) +{ + int labelLength = strlen(label); + assert(labelLength <= length); + int leftPad = (length - labelLength) / 2; + int rightPad = length - leftPad - labelLength; + char format[64]; + sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); + sprintf(buffer, format, "", label, ""); + return buffer; +} + +inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) +{ + ccprintf(os, " %16s | %#018x %s %#-018x \n", + title, a, (a == b) ? "|" : "X", b); +} + +inline void printColumnLabels(ostream & os) +{ + static char * regLabel = genCenteredLabel(16, new char[17], "Register"); + static char * m5Label = genCenteredLabel(18, new char[18], "M5"); + static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); + ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); + ccprintf(os, "--------------------+-----------------------+-----------------------\n"); +} + +inline void printSectionHeader(ostream & os, char * name) +{ + char sectionString[70]; + genCenteredLabel(69, sectionString, name); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +inline void printLevelHeader(ostream & os, int level) +{ + char sectionString[70]; + char levelName[70]; + sprintf(levelName, "Trap stack level %d", level); + genCenteredLabel(69, sectionString, levelName); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +#endif void Trace::InstRecord::dump(ostream &outs) @@ -229,40 +283,172 @@ 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; + bool diffTnpc = false; + bool diffTstate = false; + bool diffTt = false; + bool diffTba = false; + bool diffHpstate = false; + bool diffHtstate = false; + bool diffHtba = false; + bool diffPstate = false; + bool diffY = false; + bool diffCcr = false; + bool diffTl = false; + bool diffGl = false; + bool diffAsi = false; + bool diffPil = false; + bool diffCwp = false; + bool diffCansave = false; + bool diffCanrestore = false; + bool diffOtherwin = false; + bool diffCleanwin = false; Addr m5Pc, lgnPc; if(!staticInst->isMicroOp() || staticInst->isLastMicroOp()) { while (!compared) { - m5Pc = PC & TheISA::PAddrImplMask; - lgnPc = shared_data->pc & TheISA::PAddrImplMask; if (shared_data->flags == OWN_M5) { + m5Pc = PC & TheISA::PAddrImplMask; + lgnPc = shared_data->pc & TheISA::PAddrImplMask; if (lgnPc != m5Pc) diffPC = true; - if (shared_data->instruction != staticInst->machInst) + + if (shared_data->cycle_count != + thread->getCpuPtr()->instCount()) + diffCC = true; + + if (shared_data->instruction != + (SparcISA::MachInst)staticInst->machInst) { diffInst = true; - for (int i = 0; i < TheISA::NumRegularIntRegs; i++) { + } + for (int i = 0; i < TheISA::NumIntArchRegs; i++) { if (thread->readIntReg(i) != shared_data->intregs[i]) { diffRegs = true; } } - - if (diffPC || diffInst || diffRegs ) { + uint64_t oldTl = thread->readMiscReg(MISCREG_TL); + if (oldTl != shared_data->tl) + diffTl = true; + for (int i = 1; i <= MaxTL; i++) { + thread->setMiscReg(MISCREG_TL, i); + if (thread->readMiscReg(MISCREG_TPC) != + shared_data->tpc[i-1]) + diffTpc = true; + if (thread->readMiscReg(MISCREG_TNPC) != + shared_data->tnpc[i-1]) + diffTnpc = true; + if (thread->readMiscReg(MISCREG_TSTATE) != + shared_data->tstate[i-1]) + diffTstate = true; + if (thread->readMiscReg(MISCREG_TT) != + shared_data->tt[i-1]) + diffTt = true; + if (thread->readMiscReg(MISCREG_HTSTATE) != + shared_data->htstate[i-1]) + diffHtstate = true; + } + thread->setMiscReg(MISCREG_TL, oldTl); + + if(shared_data->tba != thread->readMiscReg(MISCREG_TBA)) + diffTba = true; + //When the hpstate register is read by an instruction, + //legion has bit 11 set. When it's in storage, it doesn't. + //Since we don't directly support seperate interpretations + //of the registers like that, the bit is always set to 1 and + //we just don't compare it. It's not supposed to matter + //anyway. + if((shared_data->hpstate | (1 << 11)) != thread->readMiscReg(MISCREG_HPSTATE)) + diffHpstate = true; + if(shared_data->htba != thread->readMiscReg(MISCREG_HTBA)) + diffHtba = true; + if(shared_data->pstate != thread->readMiscReg(MISCREG_PSTATE)) + diffPstate = true; + if(shared_data->y != thread->readMiscReg(MISCREG_Y)) + diffY = true; + if(shared_data->ccr != thread->readMiscReg(MISCREG_CCR)) + diffCcr = true; + if(shared_data->gl != thread->readMiscReg(MISCREG_GL)) + diffGl = true; + if(shared_data->asi != thread->readMiscReg(MISCREG_ASI)) + diffAsi = true; + if(shared_data->pil != thread->readMiscReg(MISCREG_PIL)) + diffPil = true; + if(shared_data->cwp != thread->readMiscReg(MISCREG_CWP)) + diffCwp = true; + if(shared_data->cansave != thread->readMiscReg(MISCREG_CANSAVE)) + diffCansave = true; + if(shared_data->canrestore != + thread->readMiscReg(MISCREG_CANRESTORE)) + diffCanrestore = true; + if(shared_data->otherwin != thread->readMiscReg(MISCREG_OTHERWIN)) + diffOtherwin = true; + if(shared_data->cleanwin != thread->readMiscReg(MISCREG_CLEANWIN)) + diffCleanwin = true; + + if ((diffPC || diffCC || diffInst || diffRegs || diffTpc || + diffTnpc || diffTstate || diffTt || diffHpstate || + diffHtstate || diffHtba || diffPstate || diffY || + diffCcr || diffTl || diffGl || diffAsi || diffPil || + diffCwp || diffCansave || diffCanrestore || + 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) outs << " [IntRegs]"; + if (diffTpc) + outs << " [Tpc]"; + if (diffTnpc) + outs << " [Tnpc]"; + if (diffTstate) + outs << " [Tstate]"; + if (diffTt) + outs << " [Tt]"; + if (diffHpstate) + outs << " [Hpstate]"; + if (diffHtstate) + outs << " [Htstate]"; + if (diffHtba) + outs << " [Htba]"; + if (diffPstate) + outs << " [Pstate]"; + if (diffY) + outs << " [Y]"; + if (diffCcr) + outs << " [Ccr]"; + if (diffTl) + outs << " [Tl]"; + if (diffGl) + outs << " [Gl]"; + if (diffAsi) + outs << " [Asi]"; + if (diffPil) + outs << " [Pil]"; + if (diffCwp) + outs << " [Cwp]"; + if (diffCansave) + outs << " [Cansave]"; + if (diffCanrestore) + outs << " [Canrestore]"; + if (diffOtherwin) + outs << " [Otherwin]"; + if (diffCleanwin) + outs << " [Cleanwin]"; outs << endl << endl; outs << right << setfill(' ') << setw(15) @@ -272,38 +458,127 @@ 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 << staticInst->disassemble(m5Pc, debugSymbolTable) << endl; - StaticInstPtr legionInst = StaticInst::decode(makeExtMI(shared_data->instruction, thread)); + StaticInstPtr legionInst = + StaticInst::decode(makeExtMI(shared_data->instruction, + thread)); outs << setfill(' ') << setw(15) << " Legion Inst: " << "0x" << setw(8) << setfill('0') << hex << shared_data->instruction << legionInst->disassemble(lgnPc, debugSymbolTable) - << endl; - + << endl << endl; + + printSectionHeader(outs, "General State"); + printColumnLabels(outs); + printRegPair(outs, "HPstate", + thread->readMiscReg(MISCREG_HPSTATE), + shared_data->hpstate | (1 << 11)); + printRegPair(outs, "Htba", + thread->readMiscReg(MISCREG_HTBA), + shared_data->htba); + printRegPair(outs, "Pstate", + thread->readMiscReg(MISCREG_PSTATE), + shared_data->pstate); + printRegPair(outs, "Y", + thread->readMiscReg(MISCREG_Y), + shared_data->y); + printRegPair(outs, "Ccr", + thread->readMiscReg(MISCREG_CCR), + shared_data->ccr); + printRegPair(outs, "Tl", + thread->readMiscReg(MISCREG_TL), + shared_data->tl); + printRegPair(outs, "Gl", + thread->readMiscReg(MISCREG_GL), + shared_data->gl); + printRegPair(outs, "Asi", + thread->readMiscReg(MISCREG_ASI), + shared_data->asi); + printRegPair(outs, "Pil", + thread->readMiscReg(MISCREG_PIL), + shared_data->pil); + printRegPair(outs, "Cwp", + thread->readMiscReg(MISCREG_CWP), + shared_data->cwp); + printRegPair(outs, "Cansave", + thread->readMiscReg(MISCREG_CANSAVE), + shared_data->cansave); + printRegPair(outs, "Canrestore", + thread->readMiscReg(MISCREG_CANRESTORE), + shared_data->canrestore); + printRegPair(outs, "Otherwin", + thread->readMiscReg(MISCREG_OTHERWIN), + shared_data->otherwin); + printRegPair(outs, "Cleanwin", + thread->readMiscReg(MISCREG_CLEANWIN), + shared_data->cleanwin); + outs << endl; + for (int i = 1; i <= MaxTL; i++) { + printLevelHeader(outs, i); + printColumnLabels(outs); + thread->setMiscReg(MISCREG_TL, i); + printRegPair(outs, "Tpc", + thread->readMiscReg(MISCREG_TPC), + shared_data->tpc[i-1]); + printRegPair(outs, "Tnpc", + thread->readMiscReg(MISCREG_TNPC), + shared_data->tnpc[i-1]); + printRegPair(outs, "Tstate", + thread->readMiscReg(MISCREG_TSTATE), + shared_data->tstate[i-1]); + printRegPair(outs, "Tt", + thread->readMiscReg(MISCREG_TT), + shared_data->tt[i-1]); + printRegPair(outs, "Htstate", + thread->readMiscReg(MISCREG_HTSTATE), + shared_data->htstate[i-1]); + } + thread->setMiscReg(MISCREG_TL, oldTl); outs << endl; + printSectionHeader(outs, "General Purpose Registers"); static const char * regtypes[4] = {"%g", "%o", "%l", "%i"}; for(int y = 0; y < 4; y++) { for(int x = 0; x < 8; x++) { - outs << regtypes[y] << x << " " ; - outs << "0x" << hex << setw(16) << thread->readIntReg(y*8+x); - if (thread->readIntReg(y*8 + x) != shared_data->intregs[y*8+x]) + char label[8]; + sprintf(label, "%s%d", regtypes[y], x); + printRegPair(outs, label, + thread->readIntReg(y*8+x), + shared_data->intregs[y*8+x]); + /*outs << regtypes[y] << x << " " ; + outs << "0x" << hex << setw(16) + << thread->readIntReg(y*8+x); + if (thread->readIntReg(y*8 + x) + != shared_data->intregs[y*8+x]) outs << " X "; else outs << " | "; - outs << "0x" << setw(16) << hex << shared_data->intregs[y*8+x] - << endl; + outs << "0x" << setw(16) << hex + << shared_data->intregs[y*8+x] + << 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 04016347a..e880e14e4 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/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 4937589e3..72a8d4021 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -40,6 +40,11 @@ #include "cpu/o3/mips/impl.hh" #include "cpu/o3/mips/params.hh" #include "cpu/o3/mips/dyn_inst.hh" +#elif THE_ISA == SPARC_ISA + #include "cpu/o3/sparc/cpu.hh" + #include "cpu/o3/sparc/impl.hh" + #include "cpu/o3/sparc/params.hh" + #include "cpu/o3/sparc/dyn_inst.hh" #else #error "ISA-specific header files O3CPU not defined ISA" #endif 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/o3/sparc/cpu.cc b/src/cpu/o3/sparc/cpu.cc new file mode 100644 index 000000000..1546a2b88 --- /dev/null +++ b/src/cpu/o3/sparc/cpu.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004-2005 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: Gabe Black + */ + +#include "cpu/o3/sparc/impl.hh" +#include "cpu/o3/sparc/cpu_impl.hh" +#include "cpu/o3/sparc/dyn_inst.hh" + +// Force instantiation of SparcO3CPU for all the implementations that are +// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all +// classes that depend on a certain impl, into one file (sparc_impl.cc?). +template class SparcO3CPU<SparcSimpleImpl>; diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh new file mode 100644 index 000000000..c4df79832 --- /dev/null +++ b/src/cpu/o3/sparc/cpu.hh @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2004-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: Kevin Lim + */ + +#ifndef __CPU_O3_SPARC_CPU_HH__ +#define __CPU_O3_SPARC_CPU_HH__ + +#include "arch/sparc/regfile.hh" +#include "arch/sparc/types.hh" +#include "cpu/thread_context.hh" +#include "cpu/o3/cpu.hh" +#include "sim/byteswap.hh" + +namespace TheISA +{ + class ITB; + class DTB; +} + +class EndQuiesceEvent; +namespace Kernel { + class Statistics; +}; + +class TranslatingPort; + +/** + * SparcO3CPU class. Derives from the FullO3CPU class, and + * implements all ISA and implementation specific functions of the + * CPU. This is the CPU class that is used for the SimObjects, and is + * what is given to the DynInsts. Most of its state exists in the + * FullO3CPU; the state is has is mainly for ISA specific + * functionality. + */ +template <class Impl> +class SparcO3CPU : public FullO3CPU<Impl> +{ + protected: + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + typedef TheISA::MiscRegFile MiscRegFile; + + public: + typedef O3ThreadState<Impl> ImplState; + typedef O3ThreadState<Impl> Thread; + typedef typename Impl::Params Params; + + /** Constructs an AlphaO3CPU with the given parameters. */ + SparcO3CPU(Params *params); + +#if FULL_SYSTEM + /** ITB pointer. */ + SparcISA::ITB *itb; + /** DTB pointer. */ + SparcISA::DTB *dtb; +#endif + + /** Registers statistics. */ + void regStats(); + +#if FULL_SYSTEM + /** Translates instruction requestion. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return itb->translate(req, thread->getTC()); + } + + /** Translates data read request. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return dtb->translate(req, thread->getTC(), false); + } + + /** Translates data write request. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return dtb->translate(req, thread->getTC(), true); + } + +#else + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + +#endif + /** Reads a miscellaneous register. */ + MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); + + /** Initiates a squash of all in-flight instructions for a given + * thread. The source of the squash is an external update of + * state through the TC. + */ + void squashFromTC(unsigned tid); + +#if FULL_SYSTEM + /** Posts an interrupt. */ + void post_interrupt(int int_num, int index); + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + + bool simPalCheck(int palFunc, unsigned tid); + + /** Returns the Fault for any valid interrupt. */ + Fault getInterrupts(); + + /** Processes any an interrupt fault. */ + void processInterrupts(Fault interrupt); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } +#endif + + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. + */ + void syscall(int64_t callnum, int tid); + /** Gets a syscall argument. */ + IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, IntReg val, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); +#endif + + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(RequestPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(RequestPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + /** Temporary fix for the lock flag, works in the UP case. */ + bool lockFlag; +}; + +#endif // __CPU_O3_ALPHA_CPU_HH__ diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc new file mode 100644 index 000000000..81f419ee0 --- /dev/null +++ b/src/cpu/o3/sparc/cpu_builder.cc @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#include <string> + +#include "cpu/base.hh" +#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/sparc/impl.hh" +#include "cpu/o3/sparc/params.hh" +#include "cpu/o3/fu_pool.hh" +#include "sim/builder.hh" + +class DerivO3CPU : public SparcO3CPU<SparcSimpleImpl> +{ + public: + DerivO3CPU(SparcSimpleParams *p) + : SparcO3CPU<SparcSimpleImpl>(p) + { } +}; + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU) + + Param<int> clock; + Param<int> phase; + Param<int> numThreads; + Param<int> activity; + +#if FULL_SYSTEM + SimObjectParam<System *> system; + Param<int> cpu_id; + SimObjectParam<AlphaISA::ITB *> itb; + SimObjectParam<AlphaISA::DTB *> dtb; + Param<Tick> profile; + + Param<bool> do_quiesce; + Param<bool> do_checkpoint_insts; + Param<bool> do_statistics_insts; +#else + SimObjectVectorParam<Process *> workload; +#endif // FULL_SYSTEM + + SimObjectParam<BaseCPU *> checker; + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + Param<Tick> progress_interval; + + Param<unsigned> cachePorts; + + Param<unsigned> decodeToFetchDelay; + Param<unsigned> renameToFetchDelay; + Param<unsigned> iewToFetchDelay; + Param<unsigned> commitToFetchDelay; + Param<unsigned> fetchWidth; + + Param<unsigned> renameToDecodeDelay; + Param<unsigned> iewToDecodeDelay; + Param<unsigned> commitToDecodeDelay; + Param<unsigned> fetchToDecodeDelay; + Param<unsigned> decodeWidth; + + Param<unsigned> iewToRenameDelay; + Param<unsigned> commitToRenameDelay; + Param<unsigned> decodeToRenameDelay; + Param<unsigned> renameWidth; + + Param<unsigned> commitToIEWDelay; + Param<unsigned> renameToIEWDelay; + Param<unsigned> issueToExecuteDelay; + Param<unsigned> dispatchWidth; + Param<unsigned> issueWidth; + Param<unsigned> wbWidth; + Param<unsigned> wbDepth; + SimObjectParam<FUPool *> fuPool; + + Param<unsigned> iewToCommitDelay; + Param<unsigned> renameToROBDelay; + Param<unsigned> commitWidth; + Param<unsigned> squashWidth; + Param<Tick> trapLatency; + + Param<unsigned> backComSize; + Param<unsigned> forwardComSize; + + Param<std::string> predType; + Param<unsigned> localPredictorSize; + Param<unsigned> localCtrBits; + Param<unsigned> localHistoryTableSize; + Param<unsigned> localHistoryBits; + Param<unsigned> globalPredictorSize; + Param<unsigned> globalCtrBits; + Param<unsigned> globalHistoryBits; + Param<unsigned> choicePredictorSize; + Param<unsigned> choiceCtrBits; + + Param<unsigned> BTBEntries; + Param<unsigned> BTBTagSize; + + Param<unsigned> RASSize; + + Param<unsigned> LQEntries; + Param<unsigned> SQEntries; + Param<unsigned> LFSTSize; + Param<unsigned> SSITSize; + + Param<unsigned> numPhysIntRegs; + Param<unsigned> numPhysFloatRegs; + Param<unsigned> numIQEntries; + Param<unsigned> numROBEntries; + + Param<unsigned> smtNumFetchingThreads; + Param<std::string> smtFetchPolicy; + Param<std::string> smtLSQPolicy; + Param<unsigned> smtLSQThreshold; + Param<std::string> smtIQPolicy; + Param<unsigned> smtIQThreshold; + Param<std::string> smtROBPolicy; + Param<unsigned> smtROBThreshold; + Param<std::string> smtCommitPolicy; + + Param<unsigned> instShiftAmt; + + Param<bool> defer_registration; + + Param<bool> function_trace; + Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(DerivO3CPU) + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM_DFLT(phase, "clock phase", 0), + INIT_PARAM(numThreads, "number of HW thread contexts"), + INIT_PARAM_DFLT(activity, "Initial activity count", 0), + +#if FULL_SYSTEM + INIT_PARAM(system, "System object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(itb, "Instruction translation buffer"), + INIT_PARAM(dtb, "Data translation buffer"), + INIT_PARAM(profile, ""), + + INIT_PARAM(do_quiesce, ""), + INIT_PARAM(do_checkpoint_insts, ""), + INIT_PARAM(do_statistics_insts, ""), +#else + INIT_PARAM(workload, "Processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM_DFLT(checker, "Checker CPU", NULL), + + INIT_PARAM_DFLT(max_insts_any_thread, + "Terminate when any thread reaches this inst count", + 0), + INIT_PARAM_DFLT(max_insts_all_threads, + "Terminate when all threads have reached" + "this inst count", + 0), + INIT_PARAM_DFLT(max_loads_any_thread, + "Terminate when any thread reaches this load count", + 0), + INIT_PARAM_DFLT(max_loads_all_threads, + "Terminate when all threads have reached this load" + "count", + 0), + INIT_PARAM_DFLT(progress_interval, "Progress interval", 0), + + INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), + + INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), + INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), + INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" + "delay"), + INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), + INIT_PARAM(fetchWidth, "Fetch width"), + INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), + INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" + "delay"), + INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), + INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), + INIT_PARAM(decodeWidth, "Decode width"), + + INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" + "delay"), + INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), + INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), + INIT_PARAM(renameWidth, "Rename width"), + + INIT_PARAM(commitToIEWDelay, "Commit to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(renameToIEWDelay, "Rename to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" + "to the IEW stage)"), + INIT_PARAM(dispatchWidth, "Dispatch width"), + INIT_PARAM(issueWidth, "Issue width"), + INIT_PARAM(wbWidth, "Writeback width"), + INIT_PARAM(wbDepth, "Writeback depth (number of cycles it can buffer)"), + INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL), + + INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " + "delay"), + INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), + INIT_PARAM(commitWidth, "Commit width"), + INIT_PARAM(squashWidth, "Squash width"), + INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6), + + INIT_PARAM(backComSize, "Time buffer size for backwards communication"), + INIT_PARAM(forwardComSize, "Time buffer size for forward communication"), + + INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"), + INIT_PARAM(localPredictorSize, "Size of local predictor"), + INIT_PARAM(localCtrBits, "Bits per counter"), + INIT_PARAM(localHistoryTableSize, "Size of local history table"), + INIT_PARAM(localHistoryBits, "Bits for the local history"), + INIT_PARAM(globalPredictorSize, "Size of global predictor"), + INIT_PARAM(globalCtrBits, "Bits per counter"), + INIT_PARAM(globalHistoryBits, "Bits of history"), + INIT_PARAM(choicePredictorSize, "Size of choice predictor"), + INIT_PARAM(choiceCtrBits, "Bits of choice counters"), + + INIT_PARAM(BTBEntries, "Number of BTB entries"), + INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), + + INIT_PARAM(RASSize, "RAS size"), + + INIT_PARAM(LQEntries, "Number of load queue entries"), + INIT_PARAM(SQEntries, "Number of store queue entries"), + INIT_PARAM(LFSTSize, "Last fetched store table size"), + INIT_PARAM(SSITSize, "Store set ID table size"), + + INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), + INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " + "registers"), + INIT_PARAM(numIQEntries, "Number of instruction queue entries"), + INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), + + INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), + INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), + INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), + INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), + INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), + INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), + INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), + + INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(DerivO3CPU) + +CREATE_SIM_OBJECT(DerivO3CPU) +{ + DerivO3CPU *cpu; + +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + (numThreads.isValid() && numThreads >= workload.size()) ? + numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } +#endif + + SparcSimpleParams *params = new SparcSimpleParams; + + params->clock = clock; + + params->name = getInstanceName(); + params->numberOfThreads = actual_num_threads; + params->activity = activity; + +#if FULL_SYSTEM + params->system = system; + params->cpu_id = cpu_id; + params->itb = itb; + params->dtb = dtb; + params->profile = profile; + + params->do_quiesce = do_quiesce; + params->do_checkpoint_insts = do_checkpoint_insts; + params->do_statistics_insts = do_statistics_insts; +#else + params->workload = workload; +#endif // FULL_SYSTEM + + params->checker = checker; + + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->progress_interval = progress_interval; + + // + // Caches + // + params->cachePorts = cachePorts; + + params->decodeToFetchDelay = decodeToFetchDelay; + params->renameToFetchDelay = renameToFetchDelay; + params->iewToFetchDelay = iewToFetchDelay; + params->commitToFetchDelay = commitToFetchDelay; + params->fetchWidth = fetchWidth; + + params->renameToDecodeDelay = renameToDecodeDelay; + params->iewToDecodeDelay = iewToDecodeDelay; + params->commitToDecodeDelay = commitToDecodeDelay; + params->fetchToDecodeDelay = fetchToDecodeDelay; + params->decodeWidth = decodeWidth; + + params->iewToRenameDelay = iewToRenameDelay; + params->commitToRenameDelay = commitToRenameDelay; + params->decodeToRenameDelay = decodeToRenameDelay; + params->renameWidth = renameWidth; + + params->commitToIEWDelay = commitToIEWDelay; + params->renameToIEWDelay = renameToIEWDelay; + params->issueToExecuteDelay = issueToExecuteDelay; + params->dispatchWidth = dispatchWidth; + params->issueWidth = issueWidth; + params->wbWidth = wbWidth; + params->wbDepth = wbDepth; + params->fuPool = fuPool; + + params->iewToCommitDelay = iewToCommitDelay; + params->renameToROBDelay = renameToROBDelay; + params->commitWidth = commitWidth; + params->squashWidth = squashWidth; + params->trapLatency = trapLatency; + + params->backComSize = backComSize; + params->forwardComSize = forwardComSize; + + params->predType = predType; + params->localPredictorSize = localPredictorSize; + params->localCtrBits = localCtrBits; + params->localHistoryTableSize = localHistoryTableSize; + params->localHistoryBits = localHistoryBits; + params->globalPredictorSize = globalPredictorSize; + params->globalCtrBits = globalCtrBits; + params->globalHistoryBits = globalHistoryBits; + params->choicePredictorSize = choicePredictorSize; + params->choiceCtrBits = choiceCtrBits; + + params->BTBEntries = BTBEntries; + params->BTBTagSize = BTBTagSize; + + params->RASSize = RASSize; + + params->LQEntries = LQEntries; + params->SQEntries = SQEntries; + + params->SSITSize = SSITSize; + params->LFSTSize = LFSTSize; + + params->numPhysIntRegs = numPhysIntRegs; + params->numPhysFloatRegs = numPhysFloatRegs; + params->numIQEntries = numIQEntries; + params->numROBEntries = numROBEntries; + + params->smtNumFetchingThreads = smtNumFetchingThreads; + + // Default smtFetchPolicy to "RoundRobin", if necessary. + std::string round_robin_policy = "RoundRobin"; + std::string single_thread = "SingleThread"; + + if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) + params->smtFetchPolicy = round_robin_policy; + else + params->smtFetchPolicy = smtFetchPolicy; + + params->smtIQPolicy = smtIQPolicy; + params->smtLSQPolicy = smtLSQPolicy; + params->smtLSQThreshold = smtLSQThreshold; + params->smtROBPolicy = smtROBPolicy; + params->smtROBThreshold = smtROBThreshold; + params->smtCommitPolicy = smtCommitPolicy; + + params->instShiftAmt = 2; + + params->deferRegistration = defer_registration; + + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + + cpu = new DerivO3CPU(params); + + return cpu; +} + +REGISTER_SIM_OBJECT("DerivO3CPU", DerivO3CPU) + diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh new file mode 100644 index 000000000..536a620bf --- /dev/null +++ b/src/cpu/o3/sparc/cpu_impl.hh @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#include "config/use_checker.hh" + +#include "arch/sparc/faults.hh" +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/miscregfile.hh" +#include "base/cprintf.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/checker/thread_context.hh" +#include "sim/sim_events.hh" +#include "sim/stats.hh" + +#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/sparc/params.hh" +#include "cpu/o3/sparc/thread_context.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/thread_state.hh" + +#if FULL_SYSTEM +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/kernel_stats.hh" +#include "cpu/quiesce_event.hh" +#include "sim/sim_exit.hh" +#include "sim/system.hh" +#endif + +template <class Impl> +SparcO3CPU<Impl>::SparcO3CPU(Params *params) +#if FULL_SYSTEM + : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) +#else + : FullO3CPU<Impl>(params) +#endif +{ + DPRINTF(O3CPU, "Creating SparcO3CPU object.\n"); + + // Setup any thread state. + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + // SMT is not supported in FS mode yet. + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0); + this->thread[i]->setStatus(ThreadContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(O3CPU, "Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], i); + + this->thread[i]->setStatus(ThreadContext::Suspended); + + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new Thread(this, i, dummy_proc, i); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + ThreadContext *tc; + + // Setup the TC that will serve as the interface to the threads/CPU. + SparcTC<Impl> *sparc_tc = new SparcTC<Impl>; + + tc = sparc_tc; + + // If we're using a checker, then the TC should be the + // CheckerThreadContext. +#if USE_CHECKER + if (params->checker) { + tc = new CheckerThreadContext<SparcTC<Impl> >( + sparc_tc, this->checker); + } +#endif + + sparc_tc->cpu = this; + sparc_tc->thread = this->thread[i]; + +#if FULL_SYSTEM + // Setup quiesce event. + this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); +#endif + // Give the thread the TC. + this->thread[i]->tc = tc; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->setFuncExeInst(0); + } + + // Sets CPU pointers. These must be set at this level because the CPU + // pointers are defined to be the highest level of CPU class. + this->fetch.setCPU(this); + this->decode.setCPU(this); + this->rename.setCPU(this); + this->iew.setCPU(this); + this->commit.setCPU(this); + + this->rob.setCPU(this); + this->regFile.setCPU(this); + + lockAddr = 0; + lockFlag = false; +} + +template <class Impl> +void +SparcO3CPU<Impl>::regStats() +{ + // Register stats for everything that has stats. + this->fullCPURegStats(); + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); +} + + +template <class Impl> +TheISA::MiscReg +SparcO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template <class Impl> +TheISA::MiscReg +SparcO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscRegWithEffect(misc_reg, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +{ + this->regFile.setMiscReg(misc_reg, val, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, + unsigned tid) +{ + this->regFile.setMiscRegWithEffect(misc_reg, val, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::squashFromTC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateTCEvent(tid); +} + +#if FULL_SYSTEM + +template <class Impl> +void +SparcO3CPU<Impl>::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (this->thread[0]->status() == ThreadContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + this->threadContexts[0]->activate(); + } +} + +template <class Impl> +Fault +SparcO3CPU<Impl>::hwrei(unsigned tid) +{ + panic("This doesn't make sense for SPARC\n"); + return NoFault; +} + +template <class Impl> +bool +SparcO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) +{ + panic("This doesn't make sense for SPARC\n"); + return true; +} + +template <class Impl> +Fault +SparcO3CPU<Impl>::getInterrupts() +{ + // Check if there are any outstanding interrupts + return this->interrupts.getInterrupt(this->threadContexts[0]); +} + +template <class Impl> +void +SparcO3CPU<Impl>::processInterrupts(Fault interrupt) +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + // @todo: Possibly consolidate the interrupt checking code. + // @todo: Allow other threads to handle interrupts. + + assert(interrupt != NoFault); + this->interrupts.updateIntrInfo(this->threadContexts[0]); + + DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); + this->checkInterrupts = false; + this->trap(interrupt, 0); +} + +#endif // FULL_SYSTEM + +template <class Impl> +void +SparcO3CPU<Impl>::trap(Fault fault, unsigned tid) +{ + // Pass the thread's TC into the invoke method. + fault->invoke(this->threadContexts[tid]); +} + +#if !FULL_SYSTEM + +template <class Impl> +void +SparcO3CPU<Impl>::syscall(int64_t callnum, int tid) +{ + DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +template <class Impl> +TheISA::IntReg +SparcO3CPU<Impl>::getSyscallArg(int i, int tid) +{ + return this->readArchIntReg(SparcISA::ArgumentReg0 + i, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid) +{ + this->setArchIntReg(SparcISA::ArgumentReg0 + i, val, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) +{ + // check for error condition. SPARC syscall convention is to + // indicate success/failure in reg the carry bit of the ccr + // and put the return value itself in the standard return value reg (). + if (return_value.successful()) { + // no error, clear XCC.C + this->setMiscReg(SparcISA::MISCREG_CCR, + this->readMiscReg(SparcISA::MISCREG_CCR, tid) & 0xEE, tid); + this->setArchIntReg(SparcISA::ReturnValueReg, + return_value.value(), tid); + } else { + // got an error, set XCC.C + this->setMiscReg(SparcISA::MISCREG_CCR, + this->readMiscReg(SparcISA::MISCREG_CCR, tid) | 0x11, tid); + this->setArchIntReg(SparcISA::ReturnValueReg, + return_value.value(), tid); + } +} +#endif diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/sparc/dyn_inst.cc new file mode 100644 index 000000000..984b58f4b --- /dev/null +++ b/src/cpu/o3/sparc/dyn_inst.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 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: Gabe Black + */ + +#include "cpu/o3/sparc/dyn_inst_impl.hh" +#include "cpu/o3/sparc/impl.hh" + +// Force instantiation of SparcDynInst for all the implementations that +// are needed. +template class SparcDynInst<SparcSimpleImpl>; diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh new file mode 100644 index 000000000..f8d6bb63f --- /dev/null +++ b/src/cpu/o3/sparc/dyn_inst.hh @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#ifndef __CPU_O3_SPARC_DYN_INST_HH__ +#define __CPU_O3_SPARC_DYN_INST_HH__ + +#include "arch/sparc/isa_traits.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/sparc/impl.hh" + +class Packet; + +/** + * Mostly implementation & ISA specific SparcDynInst. As with most + * other classes in the new CPU model, it is templated on the Impl to + * allow for passing in of all types, such as the CPU type and the ISA + * type. The SparcDynInst serves as the primary interface to the CPU + * for instructions that are executing. + */ +template <class Impl> +class SparcDynInst : public BaseDynInst<Impl> +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::O3CPU O3CPU; + + public: + /** BaseDynInst constructor given a binary instruction. */ + SparcDynInst(TheISA::ExtMachInst inst, Addr PC, + Addr Pred_PC, InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + SparcDynInst(StaticInstPtr &_staticInst); + + /** Executes the instruction.*/ + Fault execute(); + + /** Initiates the access. Only valid for memory operations. */ + Fault initiateAcc(); + + /** Completes the access. Only valid for memory operations. */ + Fault completeAcc(PacketPtr pkt); + + private: + /** Initializes variables. */ + void initVars(); + + public: + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscRegWithEffect(int misc_reg) + { + return this->cpu->readMiscRegWithEffect(misc_reg, this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscReg(int misc_reg, const TheISA::MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscRegWithEffect(int misc_reg, const TheISA::MiscReg &val) + { + return this->cpu->setMiscRegWithEffect(misc_reg, val, + this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); +#else + /** Calls a syscall. */ + void syscall(int64_t callnum); +#endif + + private: + /** Physical register index of the destination registers of this + * instruction. + */ + PhysRegIndex _destRegIdx[TheISA::MaxInstDestRegs]; + + /** Physical register index of the source registers of this + * instruction. + */ + PhysRegIndex _srcRegIdx[TheISA::MaxInstSrcRegs]; + + /** Physical register index of the previous producers of the + * architected destinations. + */ + PhysRegIndex _prevDestRegIdx[TheISA::MaxInstDestRegs]; + + public: + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntReg(const StaticInst *si, int idx) + { + return this->cpu->readIntReg(_srcRegIdx[idx]); + } + + TheISA::FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(_srcRegIdx[idx], width); + } + + TheISA::FloatReg readFloatReg(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(_srcRegIdx[idx]); + } + + TheISA::FloatRegBits readFloatRegBits(const StaticInst *si, + int idx, int width) + { + return this->cpu->readFloatRegBits(_srcRegIdx[idx], width); + } + + TheISA::FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + this->cpu->setIntReg(_destRegIdx[idx], val); + BaseDynInst<Impl>::setIntReg(si, idx, val); + } + + void setFloatReg(const StaticInst *si, int idx, + TheISA::FloatReg val, int width) + { + this->cpu->setFloatReg(_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatReg(si, idx, val, width); + } + + void setFloatReg(const StaticInst *si, int idx, TheISA::FloatReg val) + { + this->cpu->setFloatReg(_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatReg(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, + TheISA::FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegBits(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, + int idx, TheISA::FloatRegBits val) + { + this->cpu->setFloatRegBits(_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegBits(si, idx, val); + } + + /** Returns the physical register index of the i'th destination + * register. + */ + PhysRegIndex renamedDestRegIdx(int idx) const + { + return _destRegIdx[idx]; + } + + /** Returns the physical register index of the i'th source register. */ + PhysRegIndex renamedSrcRegIdx(int idx) const + { + return _srcRegIdx[idx]; + } + + /** Returns the physical register index of the previous physical register + * that remapped to the same logical register index. + */ + PhysRegIndex prevDestRegIdx(int idx) const + { + return _prevDestRegIdx[idx]; + } + + /** Renames a destination register to a physical register. Also records + * the previous physical register that the logical register mapped to. + */ + void renameDestReg(int idx, + PhysRegIndex renamed_dest, + PhysRegIndex previous_rename) + { + _destRegIdx[idx] = renamed_dest; + _prevDestRegIdx[idx] = previous_rename; + } + + /** Renames a source logical register to the physical register which + * has/will produce that logical register's result. + * @todo: add in whether or not the source register is ready. + */ + void renameSrcReg(int idx, PhysRegIndex renamed_src) + { + _srcRegIdx[idx] = renamed_src; + } + + public: + /** Calculates EA part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault calcEA() + { + return this->staticInst->eaCompInst()->execute(this, this->traceData); + } + + /** Does the memory access part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault memAccess() + { + return this->staticInst->memAccInst()->execute(this, this->traceData); + } +}; + +#endif // __CPU_O3_SPARC_DYN_INST_HH__ + diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh new file mode 100644 index 000000000..210daace2 --- /dev/null +++ b/src/cpu/o3/sparc/dyn_inst_impl.hh @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#include "cpu/o3/sparc/dyn_inst.hh" + +template <class Impl> +SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst, Addr PC, + Addr Pred_PC, InstSeqNum seq_num, O3CPU *cpu) + : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) +{ + initVars(); +} + +template <class Impl> +SparcDynInst<Impl>::SparcDynInst(StaticInstPtr &_staticInst) + : BaseDynInst<Impl>(_staticInst) +{ + initVars(); +} + +template <class Impl> +void +SparcDynInst<Impl>::initVars() +{ + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } +} + +template <class Impl> +Fault +SparcDynInst<Impl>::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +SparcDynInst<Impl>::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +SparcDynInst<Impl>::completeAcc(PacketPtr pkt) +{ + this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); + + return this->fault; +} + +#if FULL_SYSTEM +template <class Impl> +Fault +SparcDynInst<Impl>::hwrei() +{ + return NoFault; +} + +template <class Impl> +void +SparcDynInst<Impl>::trap(Fault fault) +{ + this->cpu->trap(fault, this->threadNumber); +} + +template <class Impl> +bool +SparcDynInst<Impl>::simPalCheck(int palFunc) +{ + return this->cpu->simPalCheck(palFunc, this->threadNumber); +} +#else +template <class Impl> +void +SparcDynInst<Impl>::syscall(int64_t callnum) +{ + this->cpu->syscall(callnum, this->threadNumber); +} +#endif + diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/sparc/impl.hh new file mode 100644 index 000000000..0a970c2f0 --- /dev/null +++ b/src/cpu/o3/sparc/impl.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004-2005 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: Gabe Black + */ + +#ifndef __CPU_O3_SPARC_IMPL_HH__ +#define __CPU_O3_SPARC_IMPL_HH__ + +#include "arch/sparc/isa_traits.hh" + +#include "cpu/o3/sparc/params.hh" +#include "cpu/o3/cpu_policy.hh" + + +// Forward declarations. +template <class Impl> +class SparcDynInst; + +template <class Impl> +class SparcO3CPU; + +/** Implementation specific struct that defines several key types to the + * CPU, the stages within the CPU, the time buffers, and the DynInst. + * The struct defines the ISA, the CPU policy, the specific DynInst, the + * specific O3CPU, and all of the structs from the time buffers to do + * communication. + * This is one of the key things that must be defined for each hardware + * specific CPU implementation. + */ +struct SparcSimpleImpl +{ + /** The type of MachInst. */ + typedef TheISA::MachInst MachInst; + + /** The CPU policy to be used, which defines all of the CPU stages. */ + typedef SimpleCPUPolicy<SparcSimpleImpl> CPUPol; + + /** The DynInst type to be used. */ + typedef SparcDynInst<SparcSimpleImpl> DynInst; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst *. + */ + typedef RefCountingPtr<DynInst> DynInstPtr; + + /** The O3CPU type to be used. */ + typedef SparcO3CPU<SparcSimpleImpl> O3CPU; + + /** Same typedef, but for CPUType. BaseDynInst may not always use + * an O3 CPU, so it's clearer to call it CPUType instead in that + * case. + */ + typedef O3CPU CPUType; + + /** The Params to be passed to each stage. */ + typedef SparcSimpleParams Params; + + enum { + MaxWidth = 8, + MaxThreads = 4 + }; +}; + +/** The O3Impl to be used. */ +typedef SparcSimpleImpl O3CPUImpl; + +#endif // __CPU_O3_SPARC_IMPL_HH__ diff --git a/src/cpu/o3/sparc/params.hh b/src/cpu/o3/sparc/params.hh new file mode 100644 index 000000000..d399d64c4 --- /dev/null +++ b/src/cpu/o3/sparc/params.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#ifndef __CPU_O3_SPARC_PARAMS_HH__ +#define __CPU_O3_SPARC_PARAMS_HH__ + +#include "cpu/o3/cpu.hh" +#include "cpu/o3/params.hh" + +//Forward declarations +namespace SparcISA +{ + class DTB; + class ITB; +} +class MemObject; +class Process; +class System; + +/** + * This file defines the parameters that will be used for the AlphaO3CPU. + * This must be defined externally so that the Impl can have a params class + * defined that it can pass to all of the individual stages. + */ + +class SparcSimpleParams : public O3Params +{ + public: + +#if FULL_SYSTEM + SparcISA::ITB *itb; + SparcISA::DTB *dtb; +#endif +}; + +#endif // __CPU_O3_SPARC_PARAMS_HH__ diff --git a/src/cpu/o3/sparc/thread_context.cc b/src/cpu/o3/sparc/thread_context.cc new file mode 100755 index 000000000..d85aff502 --- /dev/null +++ b/src/cpu/o3/sparc/thread_context.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#include "cpu/o3/thread_context.hh" +#include "cpu/o3/thread_context_impl.hh" + +template class O3ThreadContext<SparcSimpleImpl>; + diff --git a/src/cpu/o3/sparc/thread_context.hh b/src/cpu/o3/sparc/thread_context.hh new file mode 100644 index 000000000..69d1e2d04 --- /dev/null +++ b/src/cpu/o3/sparc/thread_context.hh @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004-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: Gabe Black + */ + +#include "arch/sparc/types.hh" +#include "cpu/o3/thread_context.hh" + +template <class Impl> +class SparcTC : public O3ThreadContext<Impl> +{ + public: +#if FULL_SYSTEM + /** Returns a pointer to the ITB. */ + virtual SparcISA::ITB *getITBPtr() { return this->cpu->itb; } + + /** Returns a pointer to the DTB. */ + virtual SparcISA::DTB *getDTBPtr() { return this->cpu->dtb; } + + /** Returns pointer to the quiesce event. */ + virtual EndQuiesceEvent *getQuiesceEvent() + { + return this->thread->quiesceEvent; + } +#endif + + virtual uint64_t readNextNPC() + { + return this->cpu->readNextNPC(this->thread->readTid()); + } + + virtual void setNextNPC(uint64_t val) + { + this->cpu->setNextNPC(val, this->thread->readTid()); + } + + virtual void changeRegFileContext(TheISA::RegContextParam param, + TheISA::RegContextVal val) + { + panic("This doesn't make sense!\n"); + } + + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system + if (this->cpu->numActiveThreads()) + return 0; // don't exit simulation + else + return 1; // exit simulation + } +}; 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/SConscript b/src/dev/sparc/SConscript index 701e533a8..c37294f0c 100644 --- a/src/dev/sparc/SConscript +++ b/src/dev/sparc/SConscript @@ -37,6 +37,7 @@ Import('env') sources = [] sources += Split(''' + t1000.cc ''') # Convert file names to SCons File objects. This takes care of the diff --git a/src/dev/sparc/t1000.cc b/src/dev/sparc/t1000.cc new file mode 100644 index 000000000..4a8de77a5 --- /dev/null +++ b/src/dev/sparc/t1000.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2004-2005 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 + */ + +/** @file + * Implementation of T1000 platform. + */ + +#include <deque> +#include <string> +#include <vector> + +#include "cpu/intr_control.hh" +#include "dev/simconsole.hh" +#include "dev/sparc/t1000.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +T1000::T1000(const string &name, System *s, IntrControl *ic) + : Platform(name, ic), system(s) +{ + // set the back pointer from the system to myself + system->platform = this; +} + +Tick +T1000::intrFrequency() +{ + 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 +{ + panic("Need implementation\n"); +} + + +Addr +T1000::calcConfigAddr(int bus, int dev, int func) +{ + 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) + + SimObjectParam<System *> system; + SimObjectParam<IntrControl *> intrctrl; + +END_DECLARE_SIM_OBJECT_PARAMS(T1000) + +BEGIN_INIT_SIM_OBJECT_PARAMS(T1000) + + INIT_PARAM(system, "system"), + INIT_PARAM(intrctrl, "interrupt controller") + +END_INIT_SIM_OBJECT_PARAMS(T1000) + +CREATE_SIM_OBJECT(T1000) +{ + return new T1000(getInstanceName(), system, intrctrl); +} + +REGISTER_SIM_OBJECT("T1000", T1000) diff --git a/src/dev/sparc/t1000.hh b/src/dev/sparc/t1000.hh new file mode 100644 index 000000000..2955763a9 --- /dev/null +++ b/src/dev/sparc/t1000.hh @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004-2005 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 + */ + +/** + * @file + * Declaration of top level class for the T1000 platform chips. This class just + * retains pointers to all its children so the children can communicate. + */ + +#ifndef __DEV_T1000_HH__ +#define __DEV_T1000_HH__ + +#include "dev/platform.hh" + +class IdeController; +class System; + +class T1000 : public Platform +{ + public: + /** Pointer to the system */ + System *system; + + public: + /** + * Constructor for the Tsunami Class. + * @param name name of the object + * @param s system the object belongs to + * @param intctrl pointer to the interrupt controller + */ + T1000(const std::string &name, System *s, IntrControl *intctrl); + + /** + * Return the interrupting frequency to AlphaAccess + * @return frequency of RTC interrupts + */ + virtual Tick intrFrequency(); + + /** + * Cause the cpu to post a serial interrupt to the CPU. + */ + virtual void postConsoleInt(); + + /** + * Clear a posted CPU interrupt + */ + virtual void clearConsoleInt(); + + /** + * Cause the chipset to post a cpi interrupt to the CPU. + */ + virtual void postPciInt(int line); + + /** + * Clear a posted PCI->CPU interrupt + */ + virtual void clearPciInt(int line); + + + virtual Addr pciToDma(Addr pciAddr) const; + + /** + * Calculate the configuration address given a bus/dev/func. + */ + virtual Addr calcConfigAddr(int bus, int dev, int func); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_T1000_HH__ 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/physical.cc b/src/mem/physical.cc index 94f60ad80..6610e547d 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -65,6 +65,10 @@ PhysicalMemory::PhysicalMemory(Params *p) fatal("Could not mmap!\n"); } + //If requested, initialize all the memory to 0 + if(params()->zero) + memset(pmemAddr, 0, params()->addrRange.size()); + pagePtr = 0; } @@ -191,7 +195,7 @@ PhysicalMemory::checkLockedAddrList(Request *req) void PhysicalMemory::doFunctionalAccess(PacketPtr pkt) { - assert(pkt->getAddr() + pkt->getSize() > params()->addrRange.start && + assert(pkt->getAddr() >= params()->addrRange.start && pkt->getAddr() + pkt->getSize() <= params()->addrRange.start + params()->addrRange.size()); @@ -432,6 +436,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) Param<string> file; Param<Range<Addr> > range; Param<Tick> latency; + Param<bool> zero; END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) @@ -439,7 +444,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) INIT_PARAM_DFLT(file, "memory mapped file", ""), INIT_PARAM(range, "Device Address Range"), - INIT_PARAM(latency, "Memory access latency") + INIT_PARAM(latency, "Memory access latency"), + INIT_PARAM(zero, "Zero initialize memory") END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) @@ -449,6 +455,7 @@ CREATE_SIM_OBJECT(PhysicalMemory) p->name = getInstanceName(); p->addrRange = range; p->latency = latency; + p->zero = zero; return new PhysicalMemory(p); } diff --git a/src/mem/physical.hh b/src/mem/physical.hh index 045e61612..af88bcaa0 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -154,6 +154,7 @@ class PhysicalMemory : public MemObject std::string name; Range<Addr> addrRange; Tick latency; + bool zero; }; protected: 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/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py index 4e097543d..b8df6229e 100644 --- a/src/python/m5/objects/PhysicalMemory.py +++ b/src/python/m5/objects/PhysicalMemory.py @@ -9,6 +9,7 @@ class PhysicalMemory(MemObject): range = Param.AddrRange(AddrRange('128MB'), "Device Address") file = Param.String('', "memory mapped file") latency = Param.Latency(Parent.clock, "latency of an access") + zero = Param.Bool(False, "zero initialize memory") class DRAMMemory(PhysicalMemory): type = 'DRAMMemory' diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py index 908c3d4ad..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") @@ -29,17 +29,40 @@ class AlphaSystem(System): class SparcSystem(System): type = 'SparcSystem' _rom_base = 0xfff0000000 + _nvram_base = 0x1f11000000 + _hypervisor_desc_base = 0x1f12080000 + _partition_desc_base = 0x1f12000000 # ROM for OBP/Reset/Hypervisor rom = Param.PhysicalMemory(PhysicalMemory(range = AddrRange(_rom_base, size = '8MB')), "Memory to hold the ROM data") + # nvram + nvram = Param.PhysicalMemory( + PhysicalMemory(range = AddrRange(_nvram_base, size = '8kB')), + "Memory to hold the nvram data") + # hypervisor description + hypervisor_desc = Param.PhysicalMemory( + PhysicalMemory(range = AddrRange(_hypervisor_desc_base, size = '8kB')), + "Memory to hold the hypervisor description") + # partition description + partition_desc = Param.PhysicalMemory( + PhysicalMemory(range = AddrRange(_partition_desc_base, size = '8kB')), + "Memory to hold the partition description") reset_addr = Param.Addr(_rom_base, "Address to load ROM at") hypervisor_addr = Param.Addr(Addr('64kB') + _rom_base, "Address to load hypervisor at") openboot_addr = Param.Addr(Addr('512kB') + _rom_base, "Address to load openboot at") + nvram_addr = Param.Addr(_nvram_base, "Address to put the nvram") + hypervisor_desc_addr = Param.Addr(_hypervisor_desc_base, + "Address for the hypervisor description") + partition_desc_addr = Param.Addr(_partition_desc_base, + "Address for the partition description") reset_bin = Param.String("file that contains the reset code") hypervisor_bin = Param.String("file that contains the hypervisor code") openboot_bin = Param.String("file that contains the openboot code") + nvram_bin = Param.String("file that contains the contents of nvram") + hypervisor_desc_bin = Param.String("file that contains the hypervisor description") + partition_desc_bin = Param.String("file that contains the partition description") diff --git a/src/python/m5/objects/T1000.py b/src/python/m5/objects/T1000.py new file mode 100644 index 000000000..79195d976 --- /dev/null +++ b/src/python/m5/objects/T1000.py @@ -0,0 +1,82 @@ +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice, IsaFake, BadAddr +from Uart import Uart8250 +from Platform import Platform +from SimConsole import SimConsole, ConsoleListener + +class T1000(Platform): + type = 'T1000' + system = Param.System(Parent.any, "system") + + 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!") + + 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.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; + + +} + + + + + + + + |