/*
+ * 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
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
#include "arch/utility.hh"
#include "base/bigint.hh"
#include "config/the_isa.hh"
+#include "cpu/inorder/resources/cache_unit.hh"
#include "cpu/inorder/resources/resource_list.hh"
#include "cpu/inorder/cpu.hh"
#include "cpu/inorder/first_stage.hh"
#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"
#include "debug/InOrderCPU.hh"
+#include "debug/InOrderCachePort.hh"
#include "debug/Interrupt.hh"
+#include "debug/Quiesce.hh"
#include "debug/RefCount.hh"
#include "debug/SkedCache.hh"
-#include "debug/Quiesce.hh"
-#include "mem/translating_port.hh"
#include "params/InOrderCPU.hh"
#include "sim/full_system.hh"
#include "sim/process.hh"
using namespace TheISA;
using namespace ThePipeline;
+InOrderCPU::CachePort::CachePort(CacheUnit *_cacheUnit,
+ const std::string& name) :
+ MasterPort(_cacheUnit->name() + name, _cacheUnit->cpu),
+ cacheUnit(_cacheUnit)
+{ }
+
+bool
+InOrderCPU::CachePort::recvTimingResp(Packet *pkt)
+{
+ if (pkt->isError())
+ DPRINTF(InOrderCachePort, "Got error packet back for address: %x\n",
+ pkt->getAddr());
+ else
+ cacheUnit->processCacheCompletion(pkt);
+
+ return true;
+}
+
+void
+InOrderCPU::CachePort::recvRetry()
+{
+ cacheUnit->recvRetry();
+}
+
InOrderCPU::TickEvent::TickEvent(InOrderCPU *c)
: Event(CPU_Tick_Pri), cpu(c)
{ }
const char *
-InOrderCPU::TickEvent::description()
+InOrderCPU::TickEvent::description() const
{
return "InOrderCPU tick event";
}
const char *
-InOrderCPU::CPUEvent::description()
+InOrderCPU::CPUEvent::description() const
{
return "InOrderCPU event";
}
void
-InOrderCPU::CPUEvent::scheduleEvent(int delay)
+InOrderCPU::CPUEvent::scheduleEvent(Cycles delay)
{
assert(!scheduled() || squashed());
- cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
+ cpu->reschedule(this, cpu->clockEdge(delay), true);
}
void
_status(Idle),
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"),
removeInstsThisCycle(false),
activityRec(params->name, NumStages, 10, params->activity),
system(params->system),
resReqCount(0),
#endif // DEBUG
drainCount(0),
- deferRegistration(false/*params->deferRegistration*/),
stageTracing(params->stageTracing),
lastRunningCycle(0),
instsPerSwitch(0)
{
- ThreadID active_threads;
cpu_params = params;
- resPool = new ResourcePool(this, params);
-
// Resize for Multithreading CPUs
thread.resize(numThreads);
+ ThreadID active_threads = params->workload.size();
if (FullSystem) {
active_threads = 1;
} else {
}
}
- // Bind the fetch & data ports from the resource pool.
- fetchPortIdx = resPool->getPortIdx(params->fetchMemPort);
- if (fetchPortIdx == 0) {
- fatal("Unable to find port to fetch instructions from.\n");
- }
-
- dataPortIdx = resPool->getPortIdx(params->dataMemPort);
- if (dataPortIdx == 0) {
- fatal("Unable to find port for data.\n");
- }
-
for (ThreadID tid = 0; tid < numThreads; ++tid) {
+ isa[tid] = params->isa[tid];
pc[tid].set(0);
lastCommittedPC[tid].set(0);
} else {
if (tid < (ThreadID)params->workload.size()) {
DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n",
- tid, params->workload[tid]->prog_fname);
+ tid, params->workload[tid]->progName());
thread[tid] =
new Thread(this, tid, params->workload[tid]);
} else {
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->switched_out && !interrupts) {
+ fatal("InOrderCPU %s has no interrupt controller.\n"
+ "Ensure createInterruptController() is called.\n", name());
+ }
+
dummyReqInst = new InOrderDynInst(this, NULL, 0, 0, 0);
dummyReqInst->setSquashed();
dummyReqInst->resetInstCount();
frontEndSked = createFrontEndSked();
faultSked = createFaultSked();
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
lockAddr = 0;
lockFlag = false;
// Schedule First Tick Event, CPU will reschedule itself from here on out.
- scheduleTickEvent(0);
+ scheduleTickEvent(Cycles(0));
}
InOrderCPU::~InOrderCPU()
committedInsts
.init(numThreads)
.name(name() + ".committedInsts")
- .desc("Number of Instructions Simulated (Per-Thread)");
+ .desc("Number of Instructions committed (Per-Thread)");
+
+ committedOps
+ .init(numThreads)
+ .name(name() + ".committedOps")
+ .desc("Number of Ops committed (Per-Thread)");
smtCommittedInsts
.init(numThreads)
.name(name() + ".smtCommittedInsts")
- .desc("Number of SMT Instructions Simulated (Per-Thread)");
+ .desc("Number of SMT Instructions committed (Per-Thread)");
totalCommittedInsts
.name(name() + ".committedInsts_total")
- .desc("Number of Instructions Simulated (Total)");
+ .desc("Number of Instructions committed (Total)");
cpi
.name(name() + ".cpi")
if (!tickEvent.scheduled()) {
if (_status == SwitchedOut) {
// increment stat
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
} else if (!activityRec.active()) {
DPRINTF(InOrderCPU, "sleeping CPU.\n");
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
timesIdled++;
} else {
//Tick next_tick = curTick() + cycles(1);
//tickEvent.schedule(next_tick);
- schedule(&tickEvent, nextCycle(curTick() + 1));
+ schedule(&tickEvent, clockEdge(Cycles(1)));
DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n",
- nextCycle(curTick() + 1));
+ clockEdge(Cycles(1)));
}
}
void
InOrderCPU::init()
{
- if (!deferRegistration) {
- registerThreadContexts();
- }
+ BaseCPU::init();
- // Set inSyscall so that the CPU doesn't squash when initially
- // setting up registers.
- for (ThreadID tid = 0; tid < numThreads; ++tid)
- thread[tid]->inSyscall = true;
+ for (ThreadID tid = 0; tid < numThreads; ++tid) {
+ // Set noSquashFromTC so that the CPU doesn't squash when initially
+ // setting up registers.
+ thread[tid]->noSquashFromTC = true;
+ // Initialise the ThreadContext's memory proxies
+ thread[tid]->initMemProxies(thread[tid]->getTC());
+ }
- if (FullSystem) {
+ 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();
}
-Port*
-InOrderCPU::getPort(const std::string &if_name, int idx)
+void
+InOrderCPU::verifyMemoryMode() const
{
- return resPool->getPort(if_name, idx);
+ if (!system->isTimingMode()) {
+ fatal("The in-order CPU requires the memory system to be in "
+ "'timing' mode.\n");
+ }
}
Fault
// 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]);
return interrupts->getInterrupt(threadContexts[0]);
}
-
void
InOrderCPU::processInterrupts(Fault interrupt)
{
}
void
-InOrderCPU::updateMemPorts()
-{
- // Update all ThreadContext's memory ports (Functional/Virtual
- // Ports)
- ThreadID size = thread.size();
- for (ThreadID i = 0; i < size; ++i)
- thread[i]->connectMemPorts(thread[i]->getTC());
-}
-
-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);
- Tick sked_tick = nextCycle(curTick() + ticks(delay));
- if (delay >= 0) {
- DPRINTF(InOrderCPU, "Scheduling CPU Event (%s) for cycle %i, [tid:%i].\n",
- eventNames[c_event], curTick() + delay, tid);
- schedule(cpu_event, sked_tick);
- } else {
- cpu_event->process();
- cpuEventRemoveList.push(cpu_event);
- }
+ Tick sked_tick = clockEdge(delay);
+ DPRINTF(InOrderCPU, "Scheduling CPU Event (%s) for cycle %i, [tid:%i].\n",
+ eventNames[c_event], curTick() + delay, tid);
+ schedule(cpu_event, sked_tick);
// 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);
//DEFAULT TO ROUND ROBIN SCHEME
//e.g. Move highest priority to end of thread list
list<ThreadID>::iterator list_begin = activeThreads.begin();
- list<ThreadID>::iterator list_end = activeThreads.end();
unsigned high_thread = *list_begin;
}
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");
}
void
-InOrderCPU::haltContext(ThreadID tid, int delay)
+InOrderCPU::haltContext(ThreadID tid)
{
DPRINTF(InOrderCPU, "[tid:%i]: Calling Halt Context...\n", tid);
- scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid], delay);
+ scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid]);
activityRec.activity();
}
}
void
-InOrderCPU::suspendContext(ThreadID tid, int delay)
+InOrderCPU::suspendContext(ThreadID tid)
{
- scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid], delay);
+ scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid]);
}
void
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));
}
// Increment thread-state's instruction count
thread[tid]->numInst++;
+ thread[tid]->numOp++;
// Increment thread-state's instruction stats
thread[tid]->numInsts++;
+ thread[tid]->numOps++;
// Count committed insts per thread stats
- committedInsts[tid]++;
+ if (!inst->isMicroop() || inst->isLastMicroop()) {
+ committedInsts[tid]++;
+
+ // Count total insts committed stat
+ totalCommittedInsts++;
+ }
- // Count total insts committed stat
- totalCommittedInsts++;
+ committedOps[tid]++;
// Count SMT-committed insts per thread stat
if (numActiveThreads() > 1) {
- smtCommittedInsts[tid]++;
+ if (!inst->isMicroop() || inst->isLastMicroop())
+ smtCommittedInsts[tid]++;
}
// Instruction-Mix Stats
}
// Check for instruction-count-based events.
- comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
+ comInstEventQueue[tid]->serviceEvents(thread[tid]->numOp);
// Finally, remove instruction from CPU
removeInst(inst);
DPRINTF(Activity, "Waking up CPU\n");
- Tick extra_cycles = tickToCycles((curTick() - 1) - lastRunningCycle);
+ Tick extra_cycles = curCycle() - lastRunningCycle;
+ if (extra_cycles != 0)
+ --extra_cycles;
idleCycles += extra_cycles;
for (int stage_num = 0; stage_num < NumStages; stage_num++) {
numCycles += extra_cycles;
- schedule(&tickEvent, nextCycle(curTick()));
+ 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);
}
TheISA::TLB*
InOrderCPU::getITBPtr()
{
- CacheUnit *itb_res =
- dynamic_cast<CacheUnit*>(resPool->getResource(fetchPortIdx));
+ CacheUnit *itb_res = resPool->getInstUnit();
return itb_res->tlb();
}
TheISA::TLB*
InOrderCPU::getDTBPtr()
{
- CacheUnit *dtb_res =
- dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
- return dtb_res->tlb();
+ return resPool->getDataUnit()->tlb();
}
-Decoder *
-InOrderCPU::getDecoderPtr()
+TheISA::Decoder *
+InOrderCPU::getDecoderPtr(unsigned tid)
{
- FetchUnit *fetch_res =
- dynamic_cast<FetchUnit*>(resPool->getResource(fetchPortIdx));
- return &fetch_res->decoder;
+ return resPool->getInstUnit()->decoder[tid];
}
Fault
InOrderCPU::read(DynInstPtr inst, Addr addr,
uint8_t *data, unsigned size, unsigned flags)
{
- //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
- // you want to run w/out caches?
- CacheUnit *cache_res =
- dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
-
- return cache_res->read(inst, addr, data, size, flags);
+ return resPool->getDataUnit()->read(inst, addr, data, size, flags);
}
Fault
InOrderCPU::write(DynInstPtr inst, uint8_t *data, unsigned size,
Addr addr, unsigned flags, uint64_t *write_res)
{
- //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
- // you want to run w/out caches?
- CacheUnit *cache_res =
- dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
- return cache_res->write(inst, data, size, addr, flags, write_res);
+ return resPool->getDataUnit()->write(inst, data, size, addr, flags,
+ write_res);
}