/* * Copyright (c) 2004-2005 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. */ #include "config/full_system.hh" #if FULL_SYSTEM #include "sim/system.hh" #else #include "sim/process.hh" #endif #include "sim/root.hh" #include "cpu/cpu_exec_context.hh" #include "cpu/exec_context.hh" #include "cpu/o3/alpha_dyn_inst.hh" #include "cpu/o3/alpha_impl.hh" #include "cpu/o3/cpu.hh" #include "sim/stat_control.hh" using namespace std; BaseFullCPU::BaseFullCPU(Params *params) : BaseCPU(params), cpu_id(0) { } void BaseFullCPU::regStats() { BaseCPU::regStats(); } template FullO3CPU::TickEvent::TickEvent(FullO3CPU *c) : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) { } template void FullO3CPU::TickEvent::process() { cpu->tick(); } template const char * FullO3CPU::TickEvent::description() { return "FullO3CPU tick event"; } //Call constructor to all the pipeline stages here template FullO3CPU::FullO3CPU(Params *params) : BaseFullCPU(params), tickEvent(this), removeInstsThisCycle(false), fetch(params), decode(params), rename(params), iew(params), commit(params), regFile(params->numPhysIntRegs, params->numPhysFloatRegs), freeList(params->numberOfThreads,//number of activeThreads TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs), rob(params->numROBEntries, params->squashWidth, params->smtROBPolicy, params->smtROBThreshold, params->numberOfThreads), scoreboard(params->numberOfThreads,//number of activeThreads TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs, TheISA::NumMiscRegs * number_of_threads, TheISA::ZeroReg), // What to pass to these time buffers? // For now just have these time buffers be pretty big. // @todo: Make these time buffer sizes parameters. timeBuffer(5, 5), fetchQueue(5, 5), decodeQueue(5, 5), renameQueue(5, 5), iewQueue(5, 5), activityBuffer(5, 0), activityCount(0), globalSeqNum(1), #if FULL_SYSTEM system(params->system), memCtrl(system->memctrl), physmem(system->physmem), mem(params->mem), #else // pTable(params->pTable), #endif // FULL_SYSTEM icacheInterface(params->icacheInterface), dcacheInterface(params->dcacheInterface), deferRegistration(params->deferRegistration) { _status = Idle; #if !FULL_SYSTEM thread.resize(number_of_threads); tids.resize(number_of_threads); #endif // The stages also need their CPU pointer setup. However this must be // done at the upper level CPU because they have pointers to the upper // level CPU, and not this FullO3CPU. // Set up Pointers to the activeThreads list for each stage fetch.setActiveThreads(&activeThreads); decode.setActiveThreads(&activeThreads); rename.setActiveThreads(&activeThreads); iew.setActiveThreads(&activeThreads); commit.setActiveThreads(&activeThreads); // Give each of the stages the time buffer they will use. fetch.setTimeBuffer(&timeBuffer); decode.setTimeBuffer(&timeBuffer); rename.setTimeBuffer(&timeBuffer); iew.setTimeBuffer(&timeBuffer); commit.setTimeBuffer(&timeBuffer); // Also setup each of the stages' queues. fetch.setFetchQueue(&fetchQueue); decode.setFetchQueue(&fetchQueue); commit.setFetchQueue(&fetchQueue); decode.setDecodeQueue(&decodeQueue); rename.setDecodeQueue(&decodeQueue); rename.setRenameQueue(&renameQueue); iew.setRenameQueue(&renameQueue); iew.setIEWQueue(&iewQueue); commit.setIEWQueue(&iewQueue); commit.setRenameQueue(&renameQueue); commit.setIEWStage(&iew); rename.setIEWStage(&iew); rename.setCommitStage(&commit); //Make Sure That this a Valid Architeture //@todo: move this up in constructor numThreads = number_of_threads; #if !FULL_SYSTEM int activeThreads = params->workload.size(); #else int activeThreads = 1; #endif assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); rename.setScoreboard(&scoreboard); iew.setScoreboard(&scoreboard); // Setup the rename map for whichever stages need it. PhysRegIndex lreg_idx = 0; PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs for (int tid=0; tid < numThreads; tid++) { bool bindRegs = (tid <= activeThreads - 1); commitRenameMap[tid].init(TheISA::NumIntRegs, params->numPhysIntRegs, lreg_idx, //Index for Logical. Regs TheISA::NumFloatRegs, params->numPhysFloatRegs, freg_idx, //Index for Float Regs TheISA::NumMiscRegs, TheISA::ZeroReg, TheISA::ZeroReg, tid, false); renameMap[tid].init(TheISA::NumIntRegs, params->numPhysIntRegs, lreg_idx, //Index for Logical. Regs TheISA::NumFloatRegs, params->numPhysFloatRegs, freg_idx, //Index for Float Regs TheISA::NumMiscRegs, TheISA::ZeroReg, TheISA::ZeroReg, tid, bindRegs); } rename.setRenameMap(renameMap); commit.setRenameMap(commitRenameMap); // Give renameMap & rename stage access to the freeList; for (int i=0; i < numThreads; i++) { renameMap[i].setFreeList(&freeList); } rename.setFreeList(&freeList); // Setup the page table for whichever stages need it. #if !FULL_SYSTEM // fetch.setPageTable(pTable); // iew.setPageTable(pTable); #endif // Setup the ROB for whichever stages need it. commit.setROB(&rob); lastRunningCycle = curTick; for (int i = 0; i < NumStages; ++i) { stageActive[i] = false; } contextSwitch = false; } template FullO3CPU::~FullO3CPU() { } template void FullO3CPU::fullCPURegStats() { BaseFullCPU::regStats(); // Register any of the FullCPU's stats here. timesIdled .name(name() + ".timesIdled") .desc("Number of times that the entire CPU went into an idle state and" " unscheduled itself") .prereq(timesIdled); idleCycles .name(name() + ".idleCycles") .desc("Total number of cycles that the CPU has spent unscheduled due " "to idling") .prereq(idleCycles); // Number of Instructions simulated // -------------------------------- // Should probably be in Base CPU but need templated // MaxThreads so put in here instead committedInsts .init(numThreads) .name(name() + ".committedInsts") .desc("Number of Instructions Simulated"); totalCommittedInsts .name(name() + ".committedInsts_total") .desc("Number of Instructions Simulated"); cpi .name(name() + ".cpi") .desc("CPI: Cycles Per Instruction") .precision(6); cpi = simTicks / committedInsts; totalCpi .name(name() + ".cpi_total") .desc("CPI: Total CPI of All Threads") .precision(6); totalCpi = simTicks / totalCommittedInsts; ipc .name(name() + ".ipc") .desc("IPC: Instructions Per Cycle") .precision(6); ipc = committedInsts / simTicks; totalIpc .name(name() + ".ipc_total") .desc("IPC: Total IPC of All Threads") .precision(6); totalIpc = totalCommittedInsts / simTicks; } template void FullO3CPU::tick() { DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); ++numCycles; activity = false; //Tick each of the stages fetch.tick(); decode.tick(); rename.tick(); iew.tick(); commit.tick(); #if !FULL_SYSTEM doContextSwitch(); #endif // Now advance the time buffers timeBuffer.advance(); fetchQueue.advance(); decodeQueue.advance(); renameQueue.advance(); iewQueue.advance(); advanceActivityBuffer(); if (removeInstsThisCycle) { cleanUpRemovedInsts(); } if (activityCount && !tickEvent.scheduled()) { tickEvent.schedule(curTick + 1); } #if !FULL_SYSTEM updateThreadPriority(); #endif } template void FullO3CPU::init() { if (deferRegistration) { return; } // Set inSyscall so that the CPU doesn't squash when initially // setting up registers. for (int i = 0; i < number_of_threads; ++i) thread[i]->inSyscall = true; registerExecContexts(); // Need to do a copy of the xc->regs into the CPU's regfile so // that it can start properly. for (int tid=0; tid < number_of_threads; tid++) { // Need to do a copy of the xc->regs into the CPU's regfile so // that it can start properly. #if FULL_SYSTEM ExecContext *src_xc = system->execContexts[tid]; #else ExecContext *src_xc = thread[tid]->getXCProxy(); #endif // Threads start in the Suspended State if (src_xc->status() != ExecContext::Suspended) { continue; } #if FULL_SYSTEM TheISA::initCPU(src_xc, src_xc->readCpuId()); #endif } // Clear inSyscall. for (int i = 0; i < number_of_threads; ++i) thread[i]->inSyscall = false; // Probably should just make a call to all the stages to init stage, // regardless of whether or not they need it. Keeps it more independent. fetch.initStage(); iew.initStage(); rename.initStage(); commit.initStage(); commit.setThreads(thread); } template void FullO3CPU::insertThread(unsigned tid) { DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); // Will change now that the PC and thread state is internal to the CPU // and not in the CPUExecContext. #if 0 #if FULL_SYSTEM ExecContext *src_xc = system->execContexts[tid]; #else CPUExecContext *src_xc = thread[tid]; #endif //Bind Int Regs to Rename Map for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { PhysRegIndex phys_reg = freeList.getIntReg(); renameMap[tid].setEntry(ireg,phys_reg); scoreboard.setReg(phys_reg); } //Bind Float Regs to Rename Map for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { PhysRegIndex phys_reg = freeList.getFloatReg(); renameMap[tid].setEntry(freg,phys_reg); scoreboard.setReg(phys_reg); } //Copy Thread Data Into RegFile this->copyFromXC(tid); //Set PC/NPC regFile.pc[tid] = src_xc->readPC(); regFile.npc[tid] = src_xc->readNextPC(); src_xc->setStatus(ExecContext::Active); activateContext(tid,1); //Reset ROB/IQ/LSQ Entries commit.rob->resetEntries(); iew.resetEntries(); #endif } template void FullO3CPU::removeThread(unsigned tid) { DPRINTF(FullCPU,"[tid:%i] Removing thread data"); #if 0 //Unbind Int Regs from Rename Map for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); scoreboard.unsetReg(phys_reg); freeList.addReg(phys_reg); } //Unbind Float Regs from Rename Map for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { PhysRegIndex phys_reg = renameMap[tid].lookup(freg); scoreboard.unsetReg(phys_reg); freeList.addReg(phys_reg); } //Copy Thread Data From RegFile /* Fix Me: * Do we really need to do this if we are removing a thread * in the sense that it's finished (exiting)? If the thread is just * being suspended we might... */ // this->copyToXC(tid); //Squash Throughout Pipeline fetch.squash(0,tid); decode.squash(tid); rename.squash(tid); assert(iew.ldstQueue.getCount(tid) == 0); //Reset ROB/IQ/LSQ Entries if (activeThreads.size() >= 1) { commit.rob->resetEntries(); iew.resetEntries(); } #endif } template void FullO3CPU::activateWhenReady(int tid) { DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" "(e.g. PhysRegs/ROB/IQ/LSQ) \n", tid); bool ready = true; if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " "Phys. Int. Regs.\n", tid); ready = false; } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " "Phys. Float. Regs.\n", tid); ready = false; } else if (commit.rob->numFreeEntries() >= commit.rob->entryAmount(activeThreads.size() + 1)) { DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " "ROB entries.\n", tid); ready = false; } else if (iew.instQueue.numFreeEntries() >= iew.instQueue.entryAmount(activeThreads.size() + 1)) { DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " "IQ entries.\n", tid); ready = false; } else if (iew.ldstQueue.numFreeEntries() >= iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " "LSQ entries.\n", tid); ready = false; } if (ready) { insertThread(tid); contextSwitch = false; cpuWaitList.remove(tid); } else { suspendContext(tid); //blocks fetch contextSwitch = true; //do waitlist cpuWaitList.push_back(tid); } } template void FullO3CPU::activateContext(int tid, int delay) { // Needs to set each stage to running as well. list::iterator isActive = find( activeThreads.begin(), activeThreads.end(), tid); if (isActive == activeThreads.end()) { //May Need to Re-code this if the delay variable is the //delay needed for thread to activate DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", tid); activeThreads.push_back(tid); } assert(_status == Idle); scheduleTickEvent(delay); // Be sure to signal that there's some activity so the CPU doesn't // deschedule itself. activityThisCycle(); fetch.wakeFromQuiesce(); _status = Running; } template void FullO3CPU::suspendContext(int tid) { DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); unscheduleTickEvent(); _status = Idle; /* //Remove From Active List, if Active list::iterator isActive = find( activeThreads.begin(), activeThreads.end(), tid); if (isActive != activeThreads.end()) { DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", tid); activeThreads.erase(isActive); } */ } template void FullO3CPU::deallocateContext(int tid) { DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); /* //Remove From Active List, if Active list::iterator isActive = find( activeThreads.begin(), activeThreads.end(), tid); if (isActive != activeThreads.end()) { DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", tid); activeThreads.erase(isActive); removeThread(tid); } */ } template void FullO3CPU::haltContext(int tid) { DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); /* //Remove From Active List, if Active list::iterator isActive = find( activeThreads.begin(), activeThreads.end(), tid); if (isActive != activeThreads.end()) { DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", tid); activeThreads.erase(isActive); removeThread(tid); } */ } template void FullO3CPU::switchOut() { panic("FullO3CPU does not have a switch out function.\n"); } template void FullO3CPU::takeOverFrom(BaseCPU *oldCPU) { BaseCPU::takeOverFrom(oldCPU); assert(!tickEvent.scheduled()); // Set all status's to active, schedule the // CPU's 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 InstSeqNum FullO3CPU::getAndIncrementInstSeq() { return globalSeqNum++; } template uint64_t FullO3CPU::readIntReg(int reg_idx) { return regFile.readIntReg(reg_idx); } template float FullO3CPU::readFloatRegSingle(int reg_idx) { return regFile.readFloatRegSingle(reg_idx); } template double FullO3CPU::readFloatRegDouble(int reg_idx) { return regFile.readFloatRegDouble(reg_idx); } template uint64_t FullO3CPU::readFloatRegInt(int reg_idx) { return regFile.readFloatRegInt(reg_idx); } template void FullO3CPU::setIntReg(int reg_idx, uint64_t val) { regFile.setIntReg(reg_idx, val); } template void FullO3CPU::setFloatRegSingle(int reg_idx, float val) { regFile.setFloatRegSingle(reg_idx, val); } template void FullO3CPU::setFloatRegDouble(int reg_idx, double val) { regFile.setFloatRegDouble(reg_idx, val); } template void FullO3CPU::setFloatRegInt(int reg_idx, uint64_t val) { regFile.setFloatRegInt(reg_idx, val); } template uint64_t FullO3CPU::readArchIntReg(int reg_idx, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); return regFile.readIntReg(phys_reg); } template float FullO3CPU::readArchFloatRegSingle(int reg_idx, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); return regFile.readFloatRegSingle(phys_reg); } template double FullO3CPU::readArchFloatRegDouble(int reg_idx, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); return regFile.readFloatRegDouble(phys_reg); } template uint64_t FullO3CPU::readArchFloatRegInt(int reg_idx, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); return regFile.readFloatRegInt(phys_reg); } template void FullO3CPU::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) { if (reg_idx == TheISA::ZeroReg) { warn("Setting r31 through ArchIntReg in CPU, cycle %i\n", curTick); } PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); regFile.setIntReg(phys_reg, val); } template void FullO3CPU::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); regFile.setFloatRegSingle(phys_reg, val); } template void FullO3CPU::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); regFile.setFloatRegDouble(phys_reg, val); } template void FullO3CPU::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) { PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); regFile.setFloatRegInt(phys_reg, val); } template uint64_t FullO3CPU::readPC(unsigned tid) { return commit.readPC(tid); } template void FullO3CPU::setPC(Addr new_PC,unsigned tid) { commit.setPC(new_PC, tid); } template uint64_t FullO3CPU::readNextPC(unsigned tid) { return commit.readNextPC(tid); } template void FullO3CPU::setNextPC(uint64_t val,unsigned tid) { commit.setNextPC(val, tid); } template typename FullO3CPU::ListIt FullO3CPU::addInst(DynInstPtr &inst) { instList.push_back(inst); return --(instList.end()); } template void FullO3CPU::instDone(unsigned tid) { // Keep an instruction count. thread[tid]->numInst++; thread[tid]->numInsts++; committedInsts[tid]++; totalCommittedInsts++; // Check for instruction-count-based events. comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); } template void FullO3CPU::addToRemoveList(DynInstPtr &inst) { removeInstsThisCycle = true; removeList.push(inst->getInstListIt()); } template void FullO3CPU::removeFrontInst(DynInstPtr &inst) { DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " "[sn:%lli]\n", inst->threadNumber, inst->readPC(), inst->seqNum); removeInstsThisCycle = true; // Remove the front instruction. removeList.push(inst->getInstListIt()); } template void FullO3CPU::removeInstsNotInROB(unsigned tid) { DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" " list.\n", tid); ListIt end_it; bool rob_empty = false; if (instList.empty()) { return; } else if (rob.isEmpty(/*tid*/)) { DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); end_it = instList.begin(); rob_empty = true; } else { end_it = (rob.readTailInst(tid))->getInstListIt(); DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); } removeInstsThisCycle = true; ListIt inst_it = instList.end(); inst_it--; // Walk through the instruction list, removing any instructions // that were inserted after the given instruction iterator, end_it. while (inst_it != end_it) { assert(!instList.empty()); bool break_loop = (inst_it == instList.begin()); squashInstIt(inst_it, tid); inst_it--; if (break_loop) break; } // If the ROB was empty, then we actually need to remove the first // instruction as well. if (rob_empty) { squashInstIt(inst_it, tid); } } template void FullO3CPU::removeInstsUntil(const InstSeqNum &seq_num, unsigned tid) { assert(!instList.empty()); removeInstsThisCycle = true; ListIt inst_iter = instList.end(); inst_iter--; DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", tid, seq_num, (*inst_iter)->seqNum); while ((*inst_iter)->seqNum > seq_num) { bool break_loop = (inst_iter == instList.begin()); squashInstIt(inst_iter, tid); inst_iter--; if (break_loop) break; } } template inline void FullO3CPU::squashInstIt(const ListIt &instIt, const unsigned &tid) { if ((*instIt)->threadNumber == tid) { DPRINTF(FullCPU, "FullCPU: Squashing instruction, " "[tid:%i] [sn:%lli] PC %#x\n", (*instIt)->threadNumber, (*instIt)->seqNum, (*instIt)->readPC()); // Mark it as squashed. (*instIt)->setSquashed(); //@todo: Formulate a consistent method for deleting //instructions from the instruction list // Remove the instruction from the list. removeList.push(instIt); } } template void FullO3CPU::cleanUpRemovedInsts() { while (!removeList.empty()) { DPRINTF(FullCPU, "FullCPU: Removing instruction, " "[tid:%i] [sn:%lli] PC %#x\n", (*removeList.front())->threadNumber, (*removeList.front())->seqNum, (*removeList.front())->readPC()); instList.erase(removeList.front()); removeList.pop(); } removeInstsThisCycle = false; } template void FullO3CPU::removeAllInsts() { instList.clear(); } template void FullO3CPU::dumpInsts() { int num = 0; ListIt inst_list_it = instList.begin(); cprintf("Dumping Instruction List\n"); while (inst_list_it != instList.end()) { cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" "Squashed:%i\n\n", num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed()); inst_list_it++; ++num; } } template void FullO3CPU::wakeDependents(DynInstPtr &inst) { iew.wakeDependents(inst); } template void FullO3CPU::wakeCPU() { if (activityCount || tickEvent.scheduled()) { return; } idleCycles += curTick - lastRunningCycle; tickEvent.schedule(curTick); } template void FullO3CPU::activityThisCycle() { if (activityBuffer[0]) { return; } activityBuffer[0] = true; activity = true; ++activityCount; DPRINTF(Activity, "Activity: %i\n", activityCount); } template void FullO3CPU::advanceActivityBuffer() { if (activityBuffer[-5]) { --activityCount; assert(activityCount >= 0); DPRINTF(Activity, "Activity: %i\n", activityCount); if (activityCount == 0) { DPRINTF(FullCPU, "No activity left, going to idle!\n"); lastRunningCycle = curTick; timesIdled++; } } activityBuffer.advance(); } template void FullO3CPU::activateStage(const StageIdx idx) { if (!stageActive[idx]) { ++activityCount; stageActive[idx] = true; DPRINTF(Activity, "Activity: %i\n", activityCount); } else { DPRINTF(Activity, "Stage %i already active.\n", idx); } // @todo: Number is hardcoded for now. Replace with parameter. assert(activityCount < 15); } template void FullO3CPU::deactivateStage(const StageIdx idx) { if (stageActive[idx]) { --activityCount; stageActive[idx] = false; DPRINTF(Activity, "Activity: %i\n", activityCount); } else { DPRINTF(Activity, "Stage %i already inactive.\n", idx); } assert(activityCount >= 0); } template int FullO3CPU::getFreeTid() { for (int i=0; i < numThreads; i++) { if (!tids[i]) { tids[i] = true; return i; } } return -1; } template void FullO3CPU::doContextSwitch() { if (contextSwitch) { //ADD CODE TO DEACTIVE THREAD HERE (???) for (int tid=0; tid < cpuWaitList.size(); tid++) { activateWhenReady(tid); } if (cpuWaitList.size() == 0) contextSwitch = true; } } template void FullO3CPU::updateThreadPriority() { if (activeThreads.size() > 1) { //DEFAULT TO ROUND ROBIN SCHEME //e.g. Move highest priority to end of thread list list::iterator list_begin = activeThreads.begin(); list::iterator list_end = activeThreads.end(); unsigned high_thread = *list_begin; activeThreads.erase(list_begin); activeThreads.push_back(high_thread); } } // Forward declaration of FullO3CPU. template class FullO3CPU;