summaryrefslogtreecommitdiff
path: root/src/cpu/ozone/cpu_impl.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/ozone/cpu_impl.hh')
-rw-r--r--src/cpu/ozone/cpu_impl.hh1188
1 files changed, 1188 insertions, 0 deletions
diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh
new file mode 100644
index 000000000..5c8b5001d
--- /dev/null
+++ b/src/cpu/ozone/cpu_impl.hh
@@ -0,0 +1,1188 @@
+/*
+ * 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: Kevin Lim
+ * Nathan Binkert
+ */
+
+#include "config/full_system.hh"
+#include "config/use_checker.hh"
+
+#include "arch/isa_traits.hh" // For MachInst
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/ozone/cpu.hh"
+#include "cpu/quiesce_event.hh"
+#include "cpu/static_inst.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+
+#if FULL_SYSTEM
+#include "arch/faults.hh"
+#include "arch/alpha/osfpal.hh"
+#include "arch/alpha/tlb.hh"
+#include "arch/alpha/types.hh"
+#include "arch/vtophys.hh"
+#include "base/callback.hh"
+#include "cpu/profile.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/faults.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/system.hh"
+#else // !FULL_SYSTEM
+#include "sim/process.hh"
+#endif // FULL_SYSTEM
+
+#if USE_CHECKER
+#include "cpu/checker/thread_context.hh"
+#endif
+
+using namespace TheISA;
+
+template <class Impl>
+OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
+{
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::TickEvent::process()
+{
+ cpu->tick();
+}
+
+template <class Impl>
+const char *
+OzoneCPU<Impl>::TickEvent::description()
+{
+ return "OzoneCPU tick event";
+}
+
+template <class Impl>
+OzoneCPU<Impl>::OzoneCPU(Params *p)
+#if FULL_SYSTEM
+ : BaseCPU(p), thread(this, 0), tickEvent(this, p->width),
+#else
+ : BaseCPU(p), thread(this, 0, p->workload[0], 0, p->mem),
+ tickEvent(this, p->width),
+#endif
+ mem(p->mem), comm(5, 5)
+{
+ frontEnd = new FrontEnd(p);
+ backEnd = new BackEnd(p);
+
+ _status = Idle;
+
+ if (p->checker) {
+
+ BaseCPU *temp_checker = p->checker;
+ checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
+ checker->setMemory(mem);
+#if FULL_SYSTEM
+ checker->setSystem(p->system);
+#endif
+ checkerTC = new CheckerThreadContext<OzoneTC>(&ozoneTC, checker);
+ thread.tc = checkerTC;
+ tc = checkerTC;
+#else
+ panic("Checker enabled but not compiled in!");
+#endif
+ } else {
+ // If checker is not being used, then the xcProxy points
+ // directly to the CPU's ExecContext.
+ checker = NULL;
+ thread.tc = &ozoneTC;
+ tc = &ozoneTC;
+ }
+
+ ozoneTC.cpu = this;
+ ozoneTC.thread = &thread;
+
+ thread.inSyscall = false;
+
+ thread.setStatus(ThreadContext::Suspended);
+#if FULL_SYSTEM
+ // Setup thread state stuff.
+ thread.cpu = this;
+ thread.setTid(0);
+
+ thread.quiesceEvent = new EndQuiesceEvent(tc);
+
+ system = p->system;
+ itb = p->itb;
+ dtb = p->dtb;
+ physmem = p->system->physmem;
+
+ if (p->profile) {
+ thread.profile = new FunctionProfile(p->system->kernelSymtab);
+ // @todo: This might be better as an ThreadContext instead of OzoneTC
+ Callback *cb =
+ new MakeCallback<OzoneTC,
+ &OzoneTC::dumpFuncProfile>(&ozoneTC);
+ registerExitCallback(cb);
+ }
+
+ // let's fill with a dummy node for now so we don't get a segfault
+ // on the first cycle when there's no node available.
+ static ProfileNode dummyNode;
+ thread.profileNode = &dummyNode;
+ thread.profilePC = 3;
+#else
+ thread.cpu = this;
+#endif // !FULL_SYSTEM
+
+ numInst = 0;
+ startNumInst = 0;
+
+ threadContexts.push_back(tc);
+
+ frontEnd->setCPU(this);
+ backEnd->setCPU(this);
+
+ frontEnd->setTC(tc);
+ backEnd->setTC(tc);
+
+ frontEnd->setThreadState(&thread);
+ backEnd->setThreadState(&thread);
+
+ frontEnd->setCommBuffer(&comm);
+ backEnd->setCommBuffer(&comm);
+
+ frontEnd->setBackEnd(backEnd);
+ backEnd->setFrontEnd(frontEnd);
+
+ globalSeqNum = 1;
+
+#if FULL_SYSTEM
+ checkInterrupts = false;
+#endif
+
+ lockFlag = 0;
+
+ // Setup rename table, initializing all values to ready.
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ thread.renameTable[i] = new DynInst(this);
+ thread.renameTable[i]->setResultReady();
+ }
+
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+
+#if !FULL_SYSTEM
+ /* Use this port to for syscall emulation writes to memory. */
+ Port *mem_port;
+ TranslatingPort *trans_port;
+ trans_port = new TranslatingPort(csprintf("%s-%d-funcport",
+ name(), 0),
+ p->workload[0]->pTable,
+ false);
+ mem_port = p->mem->getPort("functional");
+ mem_port->setPeer(trans_port);
+ trans_port->setPeer(mem_port);
+ thread.setMemPort(trans_port);
+#else
+ Port *mem_port;
+ FunctionalPort *phys_port;
+ VirtualPort *virt_port;
+ phys_port = new FunctionalPort(csprintf("%s-%d-funcport",
+ name(), 0));
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(phys_port);
+ phys_port->setPeer(mem_port);
+
+ virt_port = new VirtualPort(csprintf("%s-%d-vport",
+ name(), 0));
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(virt_port);
+ virt_port->setPeer(mem_port);
+
+ thread.setPhysPort(phys_port);
+ thread.setVirtPort(virt_port);
+#endif
+
+ DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n");
+}
+
+template <class Impl>
+OzoneCPU<Impl>::~OzoneCPU()
+{
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::switchOut()
+{
+ BaseCPU::switchOut(_sampler);
+ switchCount = 0;
+ // Front end needs state from back end, so switch out the back end first.
+ backEnd->switchOut();
+ frontEnd->switchOut();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::signalSwitched()
+{
+ // Only complete the switchout when both the front end and back
+ // end have signalled they are ready to switch.
+ if (++switchCount == 2) {
+ backEnd->doSwitchOut();
+ frontEnd->doSwitchOut();
+#if USE_CHECKER
+ if (checker)
+ checker->switchOut();
+#endif
+
+ _status = SwitchedOut;
+#ifndef NDEBUG
+ // Loop through all registers
+ for (int i = 0; i < AlphaISA::TotalNumRegs; ++i) {
+ assert(thread.renameTable[i] == frontEnd->renameTable[i]);
+
+ assert(thread.renameTable[i] == backEnd->renameTable[i]);
+
+ DPRINTF(OzoneCPU, "Checking if register %i matches.\n", i);
+ }
+#endif
+
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ }
+ assert(switchCount <= 2);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
+{
+ BaseCPU::takeOverFrom(oldCPU);
+
+ thread.trapPending = false;
+ thread.inSyscall = false;
+
+ backEnd->takeOverFrom();
+ frontEnd->takeOverFrom();
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+ assert(!tickEvent.scheduled());
+
+#ifndef NDEBUG
+ // Check rename table.
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ assert(thread.renameTable[i]->isResultReady());
+ }
+#endif
+
+ // @todo: Fix hardcoded number
+ // Clear out any old information in time buffer.
+ for (int i = 0; i < 15; ++i) {
+ comm.advance();
+ }
+
+ // if any of this CPU's ThreadContexts are active, mark the CPU as
+ // running and schedule its tick event.
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+ if (tc->status() == ThreadContext::Active &&
+ _status != Running) {
+ _status = Running;
+ tickEvent.schedule(curTick);
+ }
+ }
+ // Nothing running, change status to reflect that we're no longer
+ // switched out.
+ if (_status == SwitchedOut) {
+ _status = Idle;
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::activateContext(int thread_num, int delay)
+{
+ // Eventually change this in SMT.
+ assert(thread_num == 0);
+
+ assert(_status == Idle);
+ notIdleFraction++;
+ scheduleTickEvent(delay);
+ _status = Running;
+#if FULL_SYSTEM
+ if (thread.quiesceEvent && thread.quiesceEvent->scheduled())
+ thread.quiesceEvent->deschedule();
+#endif
+ thread.setStatus(ThreadContext::Active);
+ frontEnd->wakeFromQuiesce();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::suspendContext(int thread_num)
+{
+ // Eventually change this in SMT.
+ assert(thread_num == 0);
+ // @todo: Figure out how to initially set the status properly so
+ // this is running.
+// assert(_status == Running);
+ notIdleFraction--;
+ unscheduleTickEvent();
+ _status = Idle;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::deallocateContext(int thread_num, int delay)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::haltContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::regStats()
+{
+ using namespace Stats;
+
+ BaseCPU::regStats();
+
+ thread.numInsts
+ .name(name() + ".num_insts")
+ .desc("Number of instructions executed")
+ ;
+
+ thread.numMemRefs
+ .name(name() + ".num_refs")
+ .desc("Number of memory references")
+ ;
+
+ notIdleFraction
+ .name(name() + ".not_idle_fraction")
+ .desc("Percentage of non-idle cycles")
+ ;
+
+ idleFraction
+ .name(name() + ".idle_fraction")
+ .desc("Percentage of idle cycles")
+ ;
+
+ quiesceCycles
+ .name(name() + ".quiesce_cycles")
+ .desc("Number of cycles spent in quiesce")
+ ;
+
+ idleFraction = constant(1.0) - notIdleFraction;
+
+ frontEnd->regStats();
+ backEnd->regStats();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::resetStats()
+{
+// startNumInst = numInst;
+ notIdleFraction = (_status != Idle);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::init()
+{
+ BaseCPU::init();
+
+ // Mark this as in syscall so it won't need to squash
+ thread.inSyscall = true;
+#if FULL_SYSTEM
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+
+ // initialize CPU, including PC
+ TheISA::initCPU(tc, tc->readCpuId());
+ }
+#endif
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+
+ thread.inSyscall = false;
+}
+
+template <class Impl>
+Port *
+OzoneCPU<Impl>::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "dcache_port")
+ return backEnd->getDcachePort();
+ else if (if_name == "icache_port")
+ return frontEnd->getIcachePort();
+ else
+ panic("No Such Port\n");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::serialize(std::ostream &os)
+{
+ BaseCPU::serialize(os);
+ SERIALIZE_ENUM(_status);
+ nameOut(os, csprintf("%s.tc", name()));
+ ozoneTC.serialize(os);
+ nameOut(os, csprintf("%s.tickEvent", name()));
+ tickEvent.serialize(os);
+
+ // Use SimpleThread's ability to checkpoint to make it easier to
+ // write out the registers. Also make this static so it doesn't
+ // get instantiated multiple times (causes a panic in statistics).
+ static CPUExecContext temp;
+
+ nameOut(os, csprintf("%s.xc.0", name()));
+ temp.copyXC(thread.getXCProxy());
+ temp.serialize(os);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
+{
+ BaseCPU::unserialize(cp, section);
+ UNSERIALIZE_ENUM(_status);
+ ozoneTC.unserialize(cp, csprintf("%s.tc", section));
+ tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
+
+ // Use SimpleThread's ability to checkpoint to make it easier to
+ // read in the registers. Also make this static so it doesn't
+ // get instantiated multiple times (causes a panic in statistics).
+ static CPUExecContext temp;
+
+ temp.copyXC(thread.getXCProxy());
+ temp.unserialize(cp, csprintf("%s.xc.0", section));
+ thread.getXCProxy()->copyArchRegs(temp.getProxy());
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::copySrcTranslate(Addr src)
+{
+ panic("Copy not implemented!\n");
+ return NoFault;
+#if 0
+ static bool no_warn = true;
+ int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+ // Only support block sizes of 64 atm.
+ assert(blk_size == 64);
+ int offset = src & (blk_size - 1);
+
+ // Make sure block doesn't span page
+ if (no_warn &&
+ (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
+ (src >> 40) != 0xfffffc) {
+ warn("Copied block source spans pages %x.", src);
+ no_warn = false;
+ }
+
+ memReq->reset(src & ~(blk_size - 1), blk_size);
+
+ // translate to physical address
+ Fault fault = tc->translateDataReadReq(memReq);
+
+ assert(fault != Alignment_Fault);
+
+ if (fault == NoFault) {
+ tc->copySrcAddr = src;
+ tc->copySrcPhysAddr = memReq->paddr + offset;
+ } else {
+ tc->copySrcAddr = 0;
+ tc->copySrcPhysAddr = 0;
+ }
+ return fault;
+#endif
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::copy(Addr dest)
+{
+ panic("Copy not implemented!\n");
+ return NoFault;
+#if 0
+ static bool no_warn = true;
+ int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+ // Only support block sizes of 64 atm.
+ assert(blk_size == 64);
+ uint8_t data[blk_size];
+ //assert(tc->copySrcAddr);
+ int offset = dest & (blk_size - 1);
+
+ // Make sure block doesn't span page
+ if (no_warn &&
+ (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
+ (dest >> 40) != 0xfffffc) {
+ no_warn = false;
+ warn("Copied block destination spans pages %x. ", dest);
+ }
+
+ memReq->reset(dest & ~(blk_size -1), blk_size);
+ // translate to physical address
+ Fault fault = tc->translateDataWriteReq(memReq);
+
+ assert(fault != Alignment_Fault);
+
+ if (fault == NoFault) {
+ Addr dest_addr = memReq->paddr + offset;
+ // Need to read straight from memory since we have more than 8 bytes.
+ memReq->paddr = tc->copySrcPhysAddr;
+ tc->mem->read(memReq, data);
+ memReq->paddr = dest_addr;
+ tc->mem->write(memReq, data);
+ if (dcacheInterface) {
+ memReq->cmd = Copy;
+ memReq->completionEvent = NULL;
+ memReq->paddr = tc->copySrcPhysAddr;
+ memReq->dest = dest_addr;
+ memReq->size = 64;
+ memReq->time = curTick;
+ dcacheInterface->access(memReq);
+ }
+ }
+ return fault;
+#endif
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+Addr
+OzoneCPU<Impl>::dbg_vtophys(Addr addr)
+{
+ return vtophys(tc, addr);
+}
+#endif // FULL_SYSTEM
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (_status == Idle) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+// thread.activate();
+ // Hack for now. Otherwise might have to go through the tc, or
+ // I need to figure out what's the right thing to call.
+ activateContext(thread.readTid(), 1);
+ }
+}
+#endif // FULL_SYSTEM
+
+/* start simulation, program loaded, processor precise state initialized */
+template <class Impl>
+void
+OzoneCPU<Impl>::tick()
+{
+ DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n");
+
+ _status = Running;
+ thread.renameTable[ZeroReg]->setIntResult(0);
+ thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]->
+ setDoubleResult(0.0);
+
+ comm.advance();
+ frontEnd->tick();
+ backEnd->tick();
+
+ // check for instruction-count-based events
+ comInstEventQueue[0]->serviceEvents(numInst);
+
+ if (!tickEvent.scheduled() && _status == Running)
+ tickEvent.schedule(curTick + cycles(1));
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::squashFromTC()
+{
+ thread.inSyscall = true;
+ backEnd->generateTCEvent();
+}
+
+#if !FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::syscall(uint64_t &callnum)
+{
+ // Not sure this copy is needed, depending on how the TC proxy is made.
+ thread.renameTable.copyFrom(backEnd->renameTable);
+
+ thread.inSyscall = true;
+
+ thread.funcExeInst++;
+
+ DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst);
+
+ thread.process->syscall(callnum, tc);
+
+ thread.funcExeInst--;
+
+ thread.inSyscall = false;
+
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
+{
+ // check for error condition. Alpha syscall convention is to
+ // indicate success/failure in reg a3 (r19) and put the
+ // return value itself in the standard return value reg (v0).
+ if (return_value.successful()) {
+ // no error
+ thread.renameTable[SyscallSuccessReg]->setIntResult(0);
+ thread.renameTable[ReturnValueReg]->setIntResult(
+ return_value.value());
+ } else {
+ // got an error, return details
+ thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1);
+ thread.renameTable[ReturnValueReg]->setIntResult(
+ -return_value.value());
+ }
+}
+#else
+template <class Impl>
+Fault
+OzoneCPU<Impl>::hwrei()
+{
+ // Need to move this to ISA code
+ // May also need to make this per thread
+
+ lockFlag = false;
+ lockAddrList.clear();
+ thread.kernelStats->hwrei();
+
+ checkInterrupts = true;
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::processInterrupts()
+{
+ // 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.
+
+ // Check if there are any outstanding interrupts
+ //Handle the interrupts
+ int ipl = 0;
+ int summary = 0;
+
+ checkInterrupts = false;
+
+ if (thread.readMiscReg(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (thread.readMiscReg(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (thread.readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = intr_status();
+
+ if (interrupts) {
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ if (ipl && ipl > thread.readMiscReg(IPR_IPLR)) {
+ thread.setMiscReg(IPR_ISR, summary);
+ thread.setMiscReg(IPR_INTID, ipl);
+ // @todo: Make this more transparent
+ if (checker) {
+ checker->threadBase()->setMiscReg(IPR_ISR, summary);
+ checker->threadBase()->setMiscReg(IPR_INTID, ipl);
+ }
+ Fault fault = new InterruptFault;
+ fault->invoke(thread.getTC());
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ thread.readMiscReg(IPR_IPLR), ipl, summary);
+ }
+}
+
+template <class Impl>
+bool
+OzoneCPU<Impl>::simPalCheck(int palFunc)
+{
+ // Need to move this to ISA code
+ // May also need to make this per thread
+ thread.kernelStats->callpal(palFunc, tc);
+
+ switch (palFunc) {
+ case PAL::halt:
+ haltContext(thread.readTid());
+ if (--System::numSystemsRunning == 0)
+ exitSimLoop("all cpus halted");
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (system->breakpoint())
+ return false;
+ break;
+ }
+
+ return true;
+}
+#endif
+
+template <class Impl>
+BaseCPU *
+OzoneCPU<Impl>::OzoneTC::getCpuPtr()
+{
+ return cpu;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setCpuId(int id)
+{
+ cpu->cpuId = id;
+ thread->setCpuId(id);
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp)
+{
+ delete vp->getPeer();
+ delete vp;
+}
+#endif
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status)
+{
+ thread->setStatus(new_status);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::activate(int delay)
+{
+ cpu->activateContext(thread->readTid(), delay);
+}
+
+/// Set the status to Suspended.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::suspend()
+{
+ cpu->suspendContext(thread->readTid());
+}
+
+/// Set the status to Unallocated.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::deallocate(int delay)
+{
+ cpu->deallocateContext(thread->readTid(), delay);
+}
+
+/// Set the status to Halted.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::halt()
+{
+ cpu->haltContext(thread->readTid());
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::dumpFuncProfile()
+{
+ thread->dumpFuncProfile();
+}
+#endif
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context)
+{
+ // some things should already be set up
+#if FULL_SYSTEM
+ assert(getSystemPtr() == old_context->getSystemPtr());
+#else
+ assert(getProcessPtr() == old_context->getProcessPtr());
+#endif
+
+ // copy over functional state
+ setStatus(old_context->status());
+ copyArchRegs(old_context);
+ setCpuId(old_context->readCpuId());
+
+ thread->inst = old_context->getInst();
+#if !FULL_SYSTEM
+ setFuncExeInst(old_context->readFuncExeInst());
+#else
+ EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
+ if (other_quiesce) {
+ // Point the quiesce event's TC at this TC so that it wakes up
+ // the proper CPU.
+ other_quiesce->tc = this;
+ }
+ if (thread->quiesceEvent) {
+ thread->quiesceEvent->tc = this;
+ }
+
+ // Copy kernel stats pointer from old context.
+ thread->kernelStats = old_context->getKernelStats();
+// storeCondFailures = 0;
+ cpu->lockFlag = false;
+#endif
+
+ old_context->setStatus(ThreadContext::Unallocated);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::regStats(const std::string &name)
+{
+#if FULL_SYSTEM
+ thread->kernelStats = new Kernel::Statistics(cpu->system);
+ thread->kernelStats->regStats(name + ".kern");
+#endif
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::serialize(std::ostream &os)
+{
+ // Once serialization is added, serialize the quiesce event and
+ // kernel stats. Will need to make sure there aren't multiple
+ // things that serialize them.
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::unserialize(Checkpoint *cp, const std::string &section)
+{ }
+
+#if FULL_SYSTEM
+template <class Impl>
+EndQuiesceEvent *
+OzoneCPU<Impl>::OzoneTC::getQuiesceEvent()
+{
+ return thread->quiesceEvent;
+}
+
+template <class Impl>
+Tick
+OzoneCPU<Impl>::OzoneTC::readLastActivate()
+{
+ return thread->lastActivate;
+}
+
+template <class Impl>
+Tick
+OzoneCPU<Impl>::OzoneTC::readLastSuspend()
+{
+ return thread->lastSuspend;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::profileClear()
+{
+ thread->profileClear();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::profileSample()
+{
+ thread->profileSample();
+}
+#endif
+
+template <class Impl>
+int
+OzoneCPU<Impl>::OzoneTC::getThreadNum()
+{
+ return thread->readTid();
+}
+
+template <class Impl>
+TheISA::MachInst
+OzoneCPU<Impl>::OzoneTC::getInst()
+{
+ return thread->getInst();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::copyArchRegs(ThreadContext *tc)
+{
+ thread->PC = tc->readPC();
+ thread->nextPC = tc->readNextPC();
+
+ cpu->frontEnd->setPC(thread->PC);
+ cpu->frontEnd->setNextPC(thread->nextPC);
+
+ // First loop through the integer registers.
+ for (int i = 0; i < TheISA::NumIntRegs; ++i) {
+/* DPRINTF(OzoneCPU, "Copying over register %i, had data %lli, "
+ "now has data %lli.\n",
+ i, thread->renameTable[i]->readIntResult(),
+ tc->readIntReg(i));
+*/
+ thread->renameTable[i]->setIntResult(tc->readIntReg(i));
+ }
+
+ // Then loop through the floating point registers.
+ for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
+ int fp_idx = i + TheISA::FP_Base_DepTag;
+ thread->renameTable[fp_idx]->setIntResult(tc->readFloatRegBits(i));
+ }
+
+#if !FULL_SYSTEM
+ thread->funcExeInst = tc->readFuncExeInst();
+#endif
+
+ // Need to copy the TC values into the current rename table,
+ // copy the misc regs.
+ copyMiscRegs(tc, this);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::clearArchRegs()
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneTC::readIntReg(int reg_idx)
+{
+ return thread->renameTable[reg_idx]->readIntResult();
+}
+
+template <class Impl>
+TheISA::FloatReg
+OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx, int width)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ switch(width) {
+ case 32:
+ return thread->renameTable[idx]->readFloatResult();
+ case 64:
+ return thread->renameTable[idx]->readDoubleResult();
+ default:
+ panic("Unsupported width!");
+ return 0;
+ }
+}
+
+template <class Impl>
+double
+OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ return thread->renameTable[idx]->readFloatResult();
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx, int width)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ return thread->renameTable[idx]->readIntResult();
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ return thread->renameTable[idx]->readIntResult();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setIntReg(int reg_idx, uint64_t val)
+{
+ thread->renameTable[reg_idx]->setIntResult(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ switch(width) {
+ case 32:
+ panic("Unimplemented!");
+ break;
+ case 64:
+ thread->renameTable[idx]->setDoubleResult(val);
+ break;
+ default:
+ panic("Unsupported width!");
+ }
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+
+ thread->renameTable[idx]->setDoubleResult(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val,
+ int width)
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setPC(Addr val)
+{
+ thread->PC = val;
+ cpu->frontEnd->setPC(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setNextPC(Addr val)
+{
+ thread->nextPC = val;
+ cpu->frontEnd->setNextPC(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+TheISA::MiscReg
+OzoneCPU<Impl>::OzoneTC::readMiscReg(int misc_reg)
+{
+ return thread->miscRegFile.readReg(misc_reg);
+}
+
+template <class Impl>
+TheISA::MiscReg
+OzoneCPU<Impl>::OzoneTC::readMiscRegWithEffect(int misc_reg, Fault &fault)
+{
+ return thread->miscRegFile.readRegWithEffect(misc_reg,
+ fault, this);
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::OzoneTC::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ // Needs to setup a squash event unless we're in syscall mode
+ Fault ret_fault = thread->miscRegFile.setReg(misc_reg, val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+
+ return ret_fault;
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::OzoneTC::setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+{
+ // Needs to setup a squash event unless we're in syscall mode
+ Fault ret_fault = thread->miscRegFile.setRegWithEffect(misc_reg, val,
+ this);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+
+ return ret_fault;
+}