summaryrefslogtreecommitdiff
path: root/cpu/ozone/cpu_impl.hh
diff options
context:
space:
mode:
authorKevin Lim <ktlim@umich.edu>2006-04-22 18:45:01 -0400
committerKevin Lim <ktlim@umich.edu>2006-04-22 18:45:01 -0400
commit759ff4b91024835d3bf436b993b0f39e276c36fe (patch)
tree8811d20f2cf2638f8e8fd32afc08492f4b644ff6 /cpu/ozone/cpu_impl.hh
parenta8b03e4d017b66d7b5502a101ea5b7115827a107 (diff)
downloadgem5-759ff4b91024835d3bf436b993b0f39e276c36fe.tar.xz
Updates for OzoneCPU.
build/SConstruct: Include Ozone CPU models. cpu/cpu_models.py: Include OzoneCPU models. --HG-- extra : convert_revision : 51a016c216cacd2cc613eed79653026c2edda4b3
Diffstat (limited to 'cpu/ozone/cpu_impl.hh')
-rw-r--r--cpu/ozone/cpu_impl.hh1140
1 files changed, 1127 insertions, 13 deletions
diff --git a/cpu/ozone/cpu_impl.hh b/cpu/ozone/cpu_impl.hh
index e7ed3cfe0..36ec30b2c 100644
--- a/cpu/ozone/cpu_impl.hh
+++ b/cpu/ozone/cpu_impl.hh
@@ -26,23 +26,1137 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __CPU_OOO_CPU_OOO_IMPL_HH__
-#define __CPU_OOO_CPU_OOO_IMPL_HH__
+#include <cstdio>
+#include <cstdlib>
-#include "arch/isa_traits.hh"
+#include "arch/isa_traits.hh" // For MachInst
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/ozone/cpu.hh"
+#include "cpu/quiesce_event.hh"
+#include "cpu/static_inst.hh"
+#include "mem/base_mem.hh"
+#include "mem/mem_interface.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/vtophys.hh"
+#include "base/callback.hh"
+#include "base/remote_gdb.hh"
+#include "cpu/profile.hh"
+#include "kern/kernel_stats.hh"
+#include "mem/functional/memory_control.hh"
+#include "mem/functional/physical.hh"
+#include "sim/faults.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/system.hh"
+#else // !FULL_SYSTEM
+#include "mem/functional/functional.hh"
+#include "sim/process.hh"
+#endif // FULL_SYSTEM
+
+using namespace TheISA;
+
+template <class Impl>
+template<typename T>
+void
+OzoneCPU<Impl>::trace_data(T data) {
+ if (traceData) {
+ traceData->setData(data);
+ }
+}
+
+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>::ICacheCompletionEvent::ICacheCompletionEvent(OzoneCPU *_cpu)
+ : Event(&mainEventQueue),
+ cpu(_cpu)
+{
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::ICacheCompletionEvent::process()
+{
+ cpu->processICacheCompletion();
+}
+
+template <class Impl>
+const char *
+OzoneCPU<Impl>::ICacheCompletionEvent::description()
+{
+ return "OzoneCPU I-cache completion event";
+}
+
+template <class Impl>
+OzoneCPU<Impl>::DCacheCompletionEvent::
+DCacheCompletionEvent(OzoneCPU *_cpu,
+ DynInstPtr &_inst,
+ DCacheCompEventIt &_dcceIt)
+ : Event(&mainEventQueue),
+ cpu(_cpu),
+ inst(_inst),
+ dcceIt(_dcceIt)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::DCacheCompletionEvent::process()
+{
+ inst->setCompleted();
+
+ // Maybe remove the EA from the list of addrs?
+ cpu->eaList.clearAddr(inst->seqNum, inst->getEA());
+ cpu->dCacheCompList.erase(this->dcceIt);
+}
+
+template <class Impl>
+const char *
+OzoneCPU<Impl>::DCacheCompletionEvent::description()
+{
+ return "OzoneCPU D-cache completion event";
+}
+*/
+template <class Impl>
+OzoneCPU<Impl>::OzoneCPU(Params *p)
+#if FULL_SYSTEM
+ : BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width),
+#else
+ : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width),
+#endif
+ comm(5, 5)
+{
+ frontEnd = new FrontEnd(p);
+ backEnd = new BackEnd(p);
+
+ _status = Idle;
+ thread.xcProxy = &xcProxy;
+
+ thread.inSyscall = false;
+
+ xcProxy.cpu = this;
+ xcProxy.thread = &thread;
+
+ thread.setStatus(ExecContext::Suspended);
+#if FULL_SYSTEM
+// xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
+
+ /***** All thread state stuff *****/
+ thread.cpu = this;
+ thread.tid = 0;
+ thread.mem = p->mem;
+
+ thread.quiesceEvent = new EndQuiesceEvent(&xcProxy);
+
+ system = p->system;
+ itb = p->itb;
+ dtb = p->dtb;
+ memctrl = p->system->memctrl;
+ physmem = p->system->physmem;
+
+ if (p->profile) {
+ thread.profile = new FunctionProfile(p->system->kernelSymtab);
+ Callback *cb =
+ new MakeCallback<OzoneXC,
+ &OzoneXC::dumpFuncProfile>(&xcProxy);
+ 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
+// xc = new ExecContext(this, /* thread_num */ 0, p->workload[0], /* asid */ 0);
+ thread.cpu = this;
+ thread.tid = 0;
+ thread.process = p->workload[0];
+// thread.mem = thread.process->getMemory();
+ thread.asid = 0;
+#endif // !FULL_SYSTEM
+/*
+ icacheInterface = p->icache_interface;
+ dcacheInterface = p->dcache_interface;
+
+ cacheMemReq = new MemReq();
+ cacheMemReq->xc = xc;
+ cacheMemReq->asid = 0;
+ cacheMemReq->data = new uint8_t[64];
+*/
+ numInst = 0;
+ startNumInst = 0;
+/* numLoad = 0;
+ startNumLoad = 0;
+ lastIcacheStall = 0;
+ lastDcacheStall = 0;
+
+ issueWidth = p->issueWidth;
+*/
+ execContexts.push_back(&xcProxy);
+
+ frontEnd->setCPU(this);
+ backEnd->setCPU(this);
+
+ frontEnd->setXC(&xcProxy);
+ backEnd->setXC(&xcProxy);
+
+ frontEnd->setThreadState(&thread);
+ backEnd->setThreadState(&thread);
+
+ frontEnd->setCommBuffer(&comm);
+ backEnd->setCommBuffer(&comm);
+
+ frontEnd->setBackEnd(backEnd);
+ backEnd->setFrontEnd(frontEnd);
+
+ decoupledFrontEnd = p->decoupledFrontEnd;
+
+ globalSeqNum = 1;
+
+ checkInterrupts = false;
+/*
+ fetchRedirBranch = true;
+ fetchRedirExcp = true;
+
+ // Need to initialize the rename maps, and the head and tail pointers.
+ robHeadPtr = new DynInst(this);
+ robTailPtr = new DynInst(this);
+
+ robHeadPtr->setNextInst(robTailPtr);
+// robHeadPtr->setPrevInst(NULL);
+// robTailPtr->setNextInst(NULL);
+ robTailPtr->setPrevInst(robHeadPtr);
+
+ robHeadPtr->setCompleted();
+ robTailPtr->setCompleted();
+
+ for (int i = 0; i < ISA::TotalNumRegs; ++i) {
+ renameTable[i] = new DynInst(this);
+ commitTable[i] = new DynInst(this);
+
+ renameTable[i]->setCompleted();
+ commitTable[i]->setCompleted();
+ }
+
+#if FULL_SYSTEM
+ for (int i = 0; i < ISA::NumIntRegs; ++i) {
+ palShadowTable[i] = new DynInst(this);
+ palShadowTable[i]->setCompleted();
+ }
+#endif
+
+ // Size of cache block.
+ cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
+
+ // Create mask to get rid of offset bits.
+ cacheBlkMask = (cacheBlkSize - 1);
+
+ // Get the size of an instruction.
+ instSize = sizeof(MachInst);
+
+ // Create space to store a cache line.
+ cacheData = new uint8_t[cacheBlkSize];
+
+ cacheBlkValid = false;
+*/
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ thread.renameTable[i] = new DynInst(this);
+ thread.renameTable[i]->setCompleted();
+ }
+
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+
+#if !FULL_SYSTEM
+ pTable = p->pTable;
+#endif
+
+ DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n");
+}
+
+template <class Impl>
+OzoneCPU<Impl>::~OzoneCPU()
+{
+}
+/*
+template <class Impl>
+void
+OzoneCPU<Impl>::copyFromXC()
+{
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ if (i < TheISA::NumIntRegs) {
+ renameTable[i]->setIntResult(xc->readIntReg(i));
+ } else if (i < TheISA::NumFloatRegs) {
+ renameTable[i]->setDoubleResult(xc->readFloatRegDouble(i));
+ }
+ }
+
+ DPRINTF(OzoneCPU, "Func Exe inst is: %i\n", xc->func_exe_inst);
+ backEnd->funcExeInst = xc->func_exe_inst;
+// PC = xc->readPC();
+// nextPC = xc->regs.npc;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::copyToXC()
+{
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ if (i < TheISA::NumIntRegs) {
+ xc->setIntReg(i, renameTable[i]->readIntResult());
+ } else if (i < TheISA::NumFloatRegs) {
+ xc->setFloatRegDouble(i, renameTable[i]->readDoubleResult());
+ }
+ }
+
+ this->xc->regs.miscRegs.fpcr = this->regFile.miscRegs[tid].fpcr;
+ this->xc->regs.miscRegs.uniq = this->regFile.miscRegs[tid].uniq;
+ this->xc->regs.miscRegs.lock_flag = this->regFile.miscRegs[tid].lock_flag;
+ this->xc->regs.miscRegs.lock_addr = this->regFile.miscRegs[tid].lock_addr;
+
+ xc->func_exe_inst = backEnd->funcExeInst;
+ xc->regs.pc = PC;
+ xc->regs.npc = nextPC;
+}
+*/
+template <class Impl>
+void
+OzoneCPU<Impl>::switchOut()
+{
+ _status = SwitchedOut;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
+{
+ BaseCPU::takeOverFrom(oldCPU);
+
+ assert(!tickEvent.scheduled());
+
+ // if any of this CPU's ExecContexts are active, mark the CPU as
+ // running and schedule its tick event.
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+ if (xc->status() == ExecContext::Active &&
+ _status != Running) {
+ _status = Running;
+ tickEvent.schedule(curTick);
+ }
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::activateContext(int thread_num, int delay)
+{
+ // Eventually change this in SMT.
+ assert(thread_num == 0);
+// assert(xcProxy);
+
+ assert(_status == Idle);
+ notIdleFraction++;
+ scheduleTickEvent(delay);
+ _status = Running;
+ thread._status = ExecContext::Active;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::suspendContext(int thread_num)
+{
+ // Eventually change this in SMT.
+ assert(thread_num == 0);
+// assert(xcProxy);
+
+ assert(_status == Running);
+ notIdleFraction--;
+ unscheduleTickEvent();
+ _status = Idle;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::deallocateContext(int thread_num)
+{
+ // 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")
+ ;
+
+ 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();
+/*
+ copyFromXC();
+
+ // ALso copy over PC/nextPC. This isn't normally copied in "copyFromXC()"
+ // so that the XC doesn't mess up the PC when returning from a syscall.
+ PC = xc->readPC();
+ nextPC = xc->regs.npc;
+*/
+ // Mark this as in syscall so it won't need to squash
+ thread.inSyscall = true;
+#if FULL_SYSTEM
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+
+ // initialize CPU, including PC
+ TheISA::initCPU(xc, xc->readCpuId());
+ }
+#endif
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+
+ thread.inSyscall = false;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::serialize(std::ostream &os)
+{
+ // At this point, all DCacheCompEvents should be processed.
+
+ BaseCPU::serialize(os);
+ SERIALIZE_ENUM(_status);
+ nameOut(os, csprintf("%s.xc", name()));
+ xcProxy.serialize(os);
+ nameOut(os, csprintf("%s.tickEvent", name()));
+ tickEvent.serialize(os);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
+{
+ BaseCPU::unserialize(cp, section);
+ UNSERIALIZE_ENUM(_status);
+ xcProxy.unserialize(cp, csprintf("%s.xc", section));
+ tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
+}
+
+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 = xc->translateDataReadReq(memReq);
+
+ assert(fault != Alignment_Fault);
+
+ if (fault == NoFault) {
+ xc->copySrcAddr = src;
+ xc->copySrcPhysAddr = memReq->paddr + offset;
+ } else {
+ xc->copySrcAddr = 0;
+ xc->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(xc->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 = xc->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 = xc->copySrcPhysAddr;
+ xc->mem->read(memReq, data);
+ memReq->paddr = dest_addr;
+ xc->mem->write(memReq, data);
+ if (dcacheInterface) {
+ memReq->cmd = Copy;
+ memReq->completionEvent = NULL;
+ memReq->paddr = xc->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(&xcProxy, addr);
+}
+#endif // FULL_SYSTEM
+/*
+template <class Impl>
+void
+OzoneCPU<Impl>::processICacheCompletion()
+{
+ switch (status()) {
+ case IcacheMiss:
+ DPRINTF(OzoneCPU, "OzoneCPU: Finished Icache miss.\n");
+
+ icacheStallCycles += curTick - lastIcacheStall;
+ _status = IcacheMissComplete;
+ cacheBlkValid = true;
+// scheduleTickEvent(1);
+ break;
+ case SwitchedOut:
+ // If this CPU has been switched out due to sampling/warm-up,
+ // ignore any further status changes (e.g., due to cache
+ // misses outstanding at the time of the switch).
+ return;
+ default:
+ panic("OzoneCPU::processICacheCompletion: bad state");
+ break;
+ }
+}
+*/
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (thread._status == ExecContext::Suspended) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+// thread.activate();
+ // Hack for now. Otherwise might have to go through the xcProxy, or
+ // I need to figure out what's the right thing to call.
+ activateContext(thread.tid, 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");
+
+ thread.renameTable[ZeroReg]->setIntResult(0);
+ thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]->
+ setDoubleResult(0.0);
+
+ // General code flow:
+ // Check for any interrupts. Handle them if I do have one.
+ // Check if I have a need to fetch a new cache block. Either a bit could be
+ // set by functions indicating that I need to fetch a new block, or I could
+ // hang onto the last PC of the last cache block I fetched and compare the
+ // current PC to that. Setting a bit seems nicer but may be more error
+ // prone.
+ // Scan through the IQ to figure out if there's anything I can issue/execute
+ // Might need something close to the FU Pools to tell what instructions
+ // I can issue. How to handle loads and stores vs other insts?
+ // Extremely slow way: find first inst that can possibly issue; if it's a
+ // load or a store, then iterate through load/store queue.
+ // If I can't find instructions to execute and I've got room in the IQ
+ // (which is just a counter), then grab a few instructions out of the cache
+ // line buffer until I either run out or can execute up until my limit.
+
+ numCycles++;
+
+ traceData = NULL;
+
+// Fault fault = NoFault;
+
+#if 0 // FULL_SYSTEM
+ if (checkInterrupts && check_interrupts() && !inPalMode() &&
+ status() != IcacheMissComplete) {
+ int ipl = 0;
+ int summary = 0;
+ checkInterrupts = false;
+
+ if (readMiscReg(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ // Is this method so that if the interrupts are switched over from
+ // another CPU they'll still be handled?
+// uint64_t interrupts = cpuXC->cpu->intr_status();
+ uint64_t interrupts = intr_status();
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+
+ if (readMiscReg(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (ipl && ipl > readMiscReg(IPR_IPLR)) {
+ setMiscReg(IPR_ISR, summary);
+ setMiscReg(IPR_INTID, ipl);
+
+ Fault(new InterruptFault)->invoke(xc);
+
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ readMiscReg(IPR_IPLR), ipl, summary);
+ }
+ }
+#endif
+
+ // Make call to ISA to ensure 0 register semantics...actually because the
+ // DynInsts will generally be the register file, this should only have to
+ // happen when the xc is actually written to (during a syscall or something)
+ // maintain $r0 semantics
+// assert(renameTable[ZeroReg]->readIntResult() == 0);
+#ifdef TARGET_ALPHA
+// assert(renameTable[ZeroReg]->readDoubleResult() == 0);
+#endif // TARGET_ALPHA
+
+ comm.advance();
+ frontEnd->tick();
+ backEnd->tick();
+
+ // Do this here? For now the front end will control the PC.
+// PC = nextPC;
+
+ // check for instruction-count-based events
+ comInstEventQueue[0]->serviceEvents(numInst);
+
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::squashFromXC()
+{
+ thread.inSyscall = true;
+ backEnd->squashFromXC();
+}
+
+#if !FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::syscall()
+{
+ // Not sure this copy is needed, depending on how the XC proxy is made.
+ thread.renameTable.copyFrom(backEnd->renameTable);
+
+ thread.inSyscall = true;
+
+ thread.funcExeInst++;
+
+ DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst);
+
+ thread.process->syscall(&xcProxy);
+
+ 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
+ if (!inPalMode())
+ return new UnimplementedOpcodeFault;
+
+ thread.setNextPC(thread.readMiscReg(AlphaISA::IPR_EXC_ADDR));
+
+ // Not sure how to make a similar check in the Ozone model
+// if (!misspeculating()) {
+ kernelStats->hwrei();
+
+ checkInterrupts = true;
+// }
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+template <class Impl>
+bool
+OzoneCPU<Impl>::simPalCheck(int palFunc)
+{
+ // Need to move this to ISA code
+ // May also need to make this per thread
+ this->kernelStats->callpal(palFunc, &xcProxy);
+
+ switch (palFunc) {
+ case PAL::halt:
+ haltContext(thread.tid);
+ if (--System::numSystemsRunning == 0)
+ new SimExitEvent("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>::OzoneXC::getCpuPtr()
+{
+ return cpu;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setCpuId(int id)
+{
+ cpu->cpuId = id;
+ thread->cpuId = id;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setStatus(Status new_status)
+{
+// cpu->_status = new_status;
+ thread->_status = new_status;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::activate(int delay)
+{
+ cpu->activateContext(thread->tid, delay);
+}
+
+/// Set the status to Suspended.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::suspend()
+{
+ cpu->suspendContext(thread->tid);
+}
+
+/// Set the status to Unallocated.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::deallocate()
+{
+ cpu->deallocateContext(thread->tid);
+}
+
+/// Set the status to Halted.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::halt()
+{
+ cpu->haltContext(thread->tid);
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::dumpFuncProfile()
+{ }
+#endif
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::takeOverFrom(ExecContext *old_context)
+{ }
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::regStats(const std::string &name)
+{ }
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::serialize(std::ostream &os)
+{ }
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::unserialize(Checkpoint *cp, const std::string &section)
+{ }
+
+#if FULL_SYSTEM
+template <class Impl>
+Event *
+OzoneCPU<Impl>::OzoneXC::getQuiesceEvent()
+{
+ return thread->quiesceEvent;
+}
+
+template <class Impl>
+Tick
+OzoneCPU<Impl>::OzoneXC::readLastActivate()
+{
+ return thread->lastActivate;
+}
+
+template <class Impl>
+Tick
+OzoneCPU<Impl>::OzoneXC::readLastSuspend()
+{
+ return thread->lastSuspend;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::profileClear()
+{
+ if (thread->profile)
+ thread->profile->clear();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::profileSample()
+{
+ if (thread->profile)
+ thread->profile->sample(thread->profileNode, thread->profilePC);
+}
+#endif
+
+template <class Impl>
+int
+OzoneCPU<Impl>::OzoneXC::getThreadNum()
+{
+ return thread->tid;
+}
+
+// Also somewhat obnoxious. Really only used for the TLB fault.
+template <class Impl>
+TheISA::MachInst
+OzoneCPU<Impl>::OzoneXC::getInst()
+{
+ return thread->inst;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::copyArchRegs(ExecContext *xc)
+{
+ thread->PC = xc->readPC();
+ thread->nextPC = xc->readNextPC();
+
+ cpu->frontEnd->setPC(thread->PC);
+ cpu->frontEnd->setNextPC(thread->nextPC);
+
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ if (i < TheISA::FP_Base_DepTag) {
+ thread->renameTable[i]->setIntResult(xc->readIntReg(i));
+ } else if (i < (TheISA::FP_Base_DepTag + TheISA::NumFloatRegs)) {
+ int fp_idx = i - TheISA::FP_Base_DepTag;
+ thread->renameTable[i]->setDoubleResult(
+ xc->readFloatRegDouble(fp_idx));
+ }
+ }
+
+#if !FULL_SYSTEM
+ thread->funcExeInst = xc->readFuncExeInst();
+#endif
+
+ // Need to copy the XC values into the current rename table,
+ // copy the misc regs.
+ thread->regs.miscRegs.copyMiscRegs(xc);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::clearArchRegs()
+{
+ panic("Unimplemented!");
+}
template <class Impl>
-class OoOCPU;
+uint64_t
+OzoneCPU<Impl>::OzoneXC::readIntReg(int reg_idx)
+{
+ return thread->renameTable[reg_idx]->readIntResult();
+}
+
+template <class Impl>
+float
+OzoneCPU<Impl>::OzoneXC::readFloatRegSingle(int reg_idx)
+{
+ return thread->renameTable[reg_idx]->readFloatResult();
+}
+
+template <class Impl>
+double
+OzoneCPU<Impl>::OzoneXC::readFloatRegDouble(int reg_idx)
+{
+ return thread->renameTable[reg_idx]->readDoubleResult();
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneXC::readFloatRegInt(int reg_idx)
+{
+ return thread->renameTable[reg_idx]->readIntResult();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setIntReg(int reg_idx, uint64_t val)
+{
+ thread->renameTable[reg_idx]->setIntResult(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromXC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setFloatRegSingle(int reg_idx, float val)
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setFloatRegDouble(int reg_idx, double val)
+{
+ thread->renameTable[reg_idx]->setDoubleResult(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromXC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setFloatRegInt(int reg_idx, uint64_t val)
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setPC(Addr val)
+{
+ thread->PC = val;
+ cpu->frontEnd->setPC(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromXC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneXC::setNextPC(Addr val)
+{
+ thread->nextPC = val;
+ cpu->frontEnd->setNextPC(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromXC();
+ }
+}
+
+template <class Impl>
+TheISA::MiscReg
+OzoneCPU<Impl>::OzoneXC::readMiscReg(int misc_reg)
+{
+ return thread->regs.miscRegs.readReg(misc_reg);
+}
+
+template <class Impl>
+TheISA::MiscReg
+OzoneCPU<Impl>::OzoneXC::readMiscRegWithEffect(int misc_reg, Fault &fault)
+{
+ return thread->regs.miscRegs.readRegWithEffect(misc_reg,
+ fault, this);
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::OzoneXC::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ // Needs to setup a squash event unless we're in syscall mode
+ Fault ret_fault = thread->regs.miscRegs.setReg(misc_reg, val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromXC();
+ }
+
+ return ret_fault;
+}
template <class Impl>
-class OoODynInst;
+Fault
+OzoneCPU<Impl>::OzoneXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+{
+ // Needs to setup a squash event unless we're in syscall mode
+ Fault ret_fault = thread->regs.miscRegs.setRegWithEffect(misc_reg, val,
+ this);
-struct OoOImpl {
- typedef AlphaISA ISA;
- typedef OoOCPU<OoOImpl> OoOCPU;
- typedef OoOCPU FullCPU;
- typedef OoODynInst<OoOImpl> DynInst;
- typedef RefCountingPtr<DynInst> DynInstPtr;
-};
+ if (!thread->inSyscall) {
+ cpu->squashFromXC();
+ }
-#endif // __CPU_OOO_CPU_OOO_IMPL_HH__
+ return ret_fault;
+}