/*
* Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
#include "cpu/quiesce_event.hh"
+#include "cpu/reg_class.hh"
#include "cpu/simple_thread.hh"
#include "cpu/thread_context.hh"
#include "debug/Activity.hh"
InOrderCPU::CachePort::CachePort(CacheUnit *_cacheUnit,
const std::string& name) :
- CpuPort(_cacheUnit->name() + name, _cacheUnit->cpu),
+ MasterPort(_cacheUnit->name() + name, _cacheUnit->cpu),
cacheUnit(_cacheUnit)
{ }
}
void
-InOrderCPU::CPUEvent::scheduleEvent(int delay)
+InOrderCPU::CPUEvent::scheduleEvent(Cycles delay)
{
assert(!scheduled() || squashed());
cpu->reschedule(this, cpu->clockEdge(delay), true);
tickEvent(this),
stageWidth(params->stageWidth),
resPool(new ResourcePool(this, params)),
+ isa(numThreads, NULL),
timeBuffer(2 , 2),
dataPort(resPool->getDataUnit(), ".dcache_port"),
instPort(resPool->getInstUnit(), ".icache_port"),
resReqCount(0),
#endif // DEBUG
drainCount(0),
- deferRegistration(false/*params->deferRegistration*/),
stageTracing(params->stageTracing),
lastRunningCycle(0),
instsPerSwitch(0)
}
for (ThreadID tid = 0; tid < numThreads; ++tid) {
+ isa[tid] = params->isa[tid];
pc[tid].set(0);
lastCommittedPC[tid].set(0);
memset(intRegs[tid], 0, sizeof(intRegs[tid]));
memset(floatRegs.i[tid], 0, sizeof(floatRegs.i[tid]));
- isa[tid].clear();
+#ifdef ISA_HAS_CC_REGS
+ memset(ccRegs[tid], 0, sizeof(ccRegs[tid]));
+#endif
+ isa[tid]->clear();
// Define dummy instructions and resource requests to be used.
dummyInst[tid] = new InOrderDynInst(this,
}
// InOrderCPU always requires an interrupt controller.
- if (!params->defer_registration && !interrupts) {
+ if (!params->switched_out && !interrupts) {
fatal("InOrderCPU %s has no interrupt controller.\n"
"Ensure createInterruptController() is called.\n", name());
}
lockFlag = false;
// Schedule First Tick Event, CPU will reschedule itself from here on out.
- scheduleTickEvent(0);
+ scheduleTickEvent(Cycles(0));
}
InOrderCPU::~InOrderCPU()
} else {
//Tick next_tick = curTick() + cycles(1);
//tickEvent.schedule(next_tick);
- schedule(&tickEvent, clockEdge(1));
+ schedule(&tickEvent, clockEdge(Cycles(1)));
DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n",
- clockEdge(1));
+ clockEdge(Cycles(1)));
}
}
BaseCPU::init();
for (ThreadID tid = 0; tid < numThreads; ++tid) {
- // Set inSyscall so that the CPU doesn't squash when initially
+ // Set noSquashFromTC so that the CPU doesn't squash when initially
// setting up registers.
- thread[tid]->inSyscall = true;
+ thread[tid]->noSquashFromTC = true;
// Initialise the ThreadContext's memory proxies
thread[tid]->initMemProxies(thread[tid]->getTC());
}
- if (FullSystem && !params()->defer_registration) {
+ if (FullSystem && !params()->switched_out) {
for (ThreadID tid = 0; tid < numThreads; tid++) {
ThreadContext *src_tc = threadContexts[tid];
TheISA::initCPU(src_tc, src_tc->contextId());
}
}
- // Clear inSyscall.
+ // Clear noSquashFromTC.
for (ThreadID tid = 0; tid < numThreads; ++tid)
- thread[tid]->inSyscall = false;
+ thread[tid]->noSquashFromTC = false;
// Call Initializiation Routine for Resource Pool
resPool->init();
}
+void
+InOrderCPU::verifyMemoryMode() const
+{
+ if (!system->isTimingMode()) {
+ fatal("The in-order CPU requires the memory system to be in "
+ "'timing' mode.\n");
+ }
+}
+
Fault
InOrderCPU::hwrei(ThreadID tid)
{
// Schedule Squash Through-out Resource Pool
resPool->scheduleEvent(
(InOrderCPU::CPUEventType)ResourcePool::SquashAll,
- dummyTrapInst[tid], 0);
+ dummyTrapInst[tid], Cycles(0));
// Finally, Setup Trap to happen at end of cycle
trapContext(interrupt, tid, dummyTrapInst[tid]);
}
void
-InOrderCPU::trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
+InOrderCPU::trapContext(Fault fault, ThreadID tid, DynInstPtr inst,
+ Cycles delay)
{
scheduleCpuEvent(Trap, fault, tid, inst, delay);
trapPending[tid] = true;
}
void
-InOrderCPU::squashFromMemStall(DynInstPtr inst, ThreadID tid, int delay)
+InOrderCPU::squashFromMemStall(DynInstPtr inst, ThreadID tid,
+ Cycles delay)
{
scheduleCpuEvent(SquashFromMemStall, NoFault, tid, inst, delay);
}
void
InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault,
ThreadID tid, DynInstPtr inst,
- unsigned delay, CPUEventPri event_pri)
+ Cycles delay, CPUEventPri event_pri)
{
CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, inst,
event_pri);
// Broadcast event to the Resource Pool
// Need to reset tid just in case this is a dummy instruction
inst->setTid(tid);
- resPool->scheduleEvent(c_event, inst, 0, 0, tid);
+ // @todo: Is this really right? Should the delay not be passed on?
+ resPool->scheduleEvent(c_event, inst, Cycles(0), 0, tid);
}
bool
}
void
-InOrderCPU::deactivateContext(ThreadID tid, int delay)
+InOrderCPU::deactivateContext(ThreadID tid, Cycles delay)
{
DPRINTF(InOrderCPU,"[tid:%i]: Deactivating ...\n", tid);
}
void
-InOrderCPU::activateContext(ThreadID tid, int delay)
+InOrderCPU::activateContext(ThreadID tid, Cycles delay)
{
DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid);
}
void
-InOrderCPU::activateNextReadyContext(int delay)
+InOrderCPU::activateNextReadyContext(Cycles delay)
{
DPRINTF(InOrderCPU,"Activating next ready thread\n");
RegIndex
-InOrderCPU::flattenRegIdx(RegIndex reg_idx, RegType ®_type, ThreadID tid)
-{
- if (reg_idx < FP_Base_DepTag) {
- reg_type = IntType;
- return isa[tid].flattenIntIndex(reg_idx);
- } else if (reg_idx < Ctrl_Base_DepTag) {
- reg_type = FloatType;
- reg_idx -= FP_Base_DepTag;
- return isa[tid].flattenFloatIndex(reg_idx);
- } else {
- reg_type = MiscType;
- return reg_idx - TheISA::Ctrl_Base_DepTag;
+InOrderCPU::flattenRegIdx(RegIndex reg_idx, RegClass ®_type, ThreadID tid)
+{
+ RegIndex rel_idx;
+
+ reg_type = regIdxToClass(reg_idx, &rel_idx);
+
+ switch (reg_type) {
+ case IntRegClass:
+ return isa[tid]->flattenIntIndex(rel_idx);
+
+ case FloatRegClass:
+ return isa[tid]->flattenFloatIndex(rel_idx);
+
+ case MiscRegClass:
+ return rel_idx;
+
+ default:
+ panic("register %d out of range\n", reg_idx);
}
}
return floatRegs.i[tid][reg_idx];
}
+CCReg
+InOrderCPU::readCCReg(RegIndex reg_idx, ThreadID tid)
+{
+#ifdef ISA_HAS_CC_REGS
+ DPRINTF(CCRegs, "[tid:%i]: Reading CC. Reg %i as %x\n",
+ tid, reg_idx, ccRegs[tid][reg_idx]);
+
+ return ccRegs[tid][reg_idx];
+#else
+ panic("readCCReg: ISA does not have CC regs\n");
+#endif
+}
+
void
InOrderCPU::setIntReg(RegIndex reg_idx, uint64_t val, ThreadID tid)
{
floatRegs.f[tid][reg_idx]);
}
+void
+InOrderCPU::setCCReg(RegIndex reg_idx, CCReg val, ThreadID tid)
+{
+#ifdef ISA_HAS_CC_REGS
+ DPRINTF(CCRegs, "[tid:%i]: Setting CC. Reg %i to %x\n",
+ tid, reg_idx, val);
+ ccRegs[tid][reg_idx] = val;
+#else
+ panic("readCCReg: ISA does not have CC regs\n");
+#endif
+}
+
uint64_t
InOrderCPU::readRegOtherThread(unsigned reg_idx, ThreadID tid)
{
tid = TheISA::getTargetThread(tcBase(tid));
}
- if (reg_idx < FP_Base_DepTag) {
+ RegIndex rel_idx;
+
+ switch (regIdxToClass(reg_idx, &rel_idx)) {
+ case IntRegClass:
// Integer Register File
- return readIntReg(reg_idx, tid);
- } else if (reg_idx < Ctrl_Base_DepTag) {
+ return readIntReg(rel_idx, tid);
+
+ case FloatRegClass:
// Float Register File
- reg_idx -= FP_Base_DepTag;
- return readFloatRegBits(reg_idx, tid);
- } else {
- reg_idx -= Ctrl_Base_DepTag;
- return readMiscReg(reg_idx, tid); // Misc. Register File
+ return readFloatRegBits(rel_idx, tid);
+
+ case MiscRegClass:
+ return readMiscReg(rel_idx, tid); // Misc. Register File
+
+ default:
+ panic("register %d out of range\n", reg_idx);
}
}
+
void
InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
ThreadID tid)
tid = TheISA::getTargetThread(tcBase(tid));
}
- if (reg_idx < FP_Base_DepTag) { // Integer Register File
- setIntReg(reg_idx, val, tid);
- } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
- reg_idx -= FP_Base_DepTag;
- setFloatRegBits(reg_idx, val, tid);
- } else {
- reg_idx -= Ctrl_Base_DepTag;
- setMiscReg(reg_idx, val, tid); // Misc. Register File
+ RegIndex rel_idx;
+
+ switch (regIdxToClass(reg_idx, &rel_idx)) {
+ case IntRegClass:
+ setIntReg(rel_idx, val, tid);
+ break;
+
+ case FloatRegClass:
+ setFloatRegBits(rel_idx, val, tid);
+ break;
+
+ case CCRegClass:
+ setCCReg(rel_idx, val, tid);
+ break;
+
+ case MiscRegClass:
+ setMiscReg(rel_idx, val, tid); // Misc. Register File
+ break;
}
}
MiscReg
InOrderCPU::readMiscRegNoEffect(int misc_reg, ThreadID tid)
{
- return isa[tid].readMiscRegNoEffect(misc_reg);
+ return isa[tid]->readMiscRegNoEffect(misc_reg);
}
MiscReg
InOrderCPU::readMiscReg(int misc_reg, ThreadID tid)
{
- return isa[tid].readMiscReg(misc_reg, tcBase(tid));
+ return isa[tid]->readMiscReg(misc_reg, tcBase(tid));
}
void
InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, ThreadID tid)
{
- isa[tid].setMiscRegNoEffect(misc_reg, val);
+ isa[tid]->setMiscRegNoEffect(misc_reg, val);
}
void
InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, ThreadID tid)
{
- isa[tid].setMiscReg(misc_reg, val, tcBase(tid));
+ isa[tid]->setMiscReg(misc_reg, val, tcBase(tid));
}
numCycles += extra_cycles;
- schedule(&tickEvent, nextCycle());
+ schedule(&tickEvent, clockEdge());
}
// Lots of copied full system code...place into BaseCPU class?
}
void
-InOrderCPU::syscallContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
+InOrderCPU::syscallContext(Fault fault, ThreadID tid, DynInstPtr inst,
+ Cycles delay)
{
// Syscall must be non-speculative, so squash from last stage
unsigned squash_stage = NumStages - 1;
// Schedule Squash Through-out Resource Pool
resPool->scheduleEvent(
- (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
+ (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst,
+ Cycles(0));
scheduleCpuEvent(Syscall, fault, tid, inst, delay, Syscall_Pri);
}