gem5/src/cpu/ozone/cpu_impl.hh
Steve Reinhardt 7617dcf736 ThreadState: initialize status to Halted in constructor.
This provides a common initial status for all threads independent
of CPU model (unlike the prior situation where CPUs initialized
threads to inconsistent states).
This mostly matters for SE mode; in FS mode, ISA-specific startupCPU()
methods generally handle boot-time initialization of thread contexts
(since the right thing to do is ISA-dependent).
2009-04-15 13:18:24 -07:00

1080 lines
26 KiB
C++

/*
* 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/simple_thread.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/tlb.hh"
#include "arch/types.hh"
#include "arch/kernel_stats.hh"
#include "arch/vtophys.hh"
#include "base/callback.hh"
#include "cpu/profile.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() const
{
return "OzoneCPU tick";
}
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),
tickEvent(this, p->width),
#endif
#ifndef NDEBUG
instcount(0),
#endif
comm(5, 5)
{
frontEnd = new FrontEnd(p);
backEnd = new BackEnd(p);
_status = Idle;
if (p->checker) {
#if USE_CHECKER
BaseCPU *temp_checker = p->checker;
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
#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;
itb = p->itb;
dtb = p->dtb;
#if FULL_SYSTEM
// Setup thread state stuff.
thread.cpu = this;
thread.setTid(0);
thread.quiesceEvent = new EndQuiesceEvent(tc);
system = p->system;
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;
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
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();
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->contextId());
}
#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 SimpleThread temp;
nameOut(os, csprintf("%s.xc.0", name()));
temp.copyTC(thread.getTC());
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 SimpleThread temp;
temp.copyTC(thread.getTC());
temp.unserialize(cp, csprintf("%s.xc.0", section));
thread.getTC()->copyArchRegs(temp.getTC());
}
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>::wakeup()
{
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.threadId(), 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 + ticks(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);
}
#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();
// 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
Fault interrupt = this->interrupts->getInterrupt(thread.getTC());
if (interrupt != NoFault) {
this->interrupts->updateIntrInfo(thread.getTC());
interrupt->invoke(thread.getTC());
}
}
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.threadId());
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::setStatus(Status new_status)
{
thread->setStatus(new_status);
}
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::activate(int delay)
{
cpu->activateContext(thread->threadId(), delay);
}
/// Set the status to Suspended.
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::suspend()
{
cpu->suspendContext(thread->threadId());
}
/// Set the status to Halted.
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::halt()
{
cpu->haltContext(thread->threadId());
}
#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->cpuId());
setContextId(old_context->contextId());
thread->setInst(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::Halted);
}
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::regStats(const std::string &name)
{
#if FULL_SYSTEM
thread->kernelStats = new TheISA::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::threadId()
{
return thread->threadId();
}
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::readMiscRegNoEffect(int misc_reg)
{
return thread->miscRegFile.readRegNoEffect(misc_reg);
}
template <class Impl>
TheISA::MiscReg
OzoneCPU<Impl>::OzoneTC::readMiscReg(int misc_reg)
{
return thread->miscRegFile.readReg(misc_reg, this);
}
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
// Needs to setup a squash event unless we're in syscall mode
thread->miscRegFile.setRegNoEffect(misc_reg, val);
if (!thread->inSyscall) {
cpu->squashFromTC();
}
}
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::setMiscReg(int misc_reg, const MiscReg &val)
{
// Needs to setup a squash event unless we're in syscall mode
thread->miscRegFile.setReg(misc_reg, val, this);
if (!thread->inSyscall) {
cpu->squashFromTC();
}
}