cpu.cc
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,477 行 · 第 1/3 页
CC
1,477 行
ThreadContext *src_tc = thread[tid]->getTC();#endif // Threads start in the Suspended State if (src_tc->status() != ThreadContext::Suspended) { continue; }#if FULL_SYSTEM TheISA::initCPU(src_tc, src_tc->readCpuId());#endif } // Clear inSyscall. for (int i = 0; i < number_of_threads; ++i) thread[i]->inSyscall = false; // Initialize stages. fetch.initStage(); iew.initStage(); rename.initStage(); commit.initStage(); commit.setThreads(thread);}template <class Impl>voidFullO3CPU<Impl>::activateThread(unsigned tid){ std::list<unsigned>::iterator isActive = std::find(activeThreads.begin(), activeThreads.end(), tid); DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid); if (isActive == activeThreads.end()) { DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n", tid); activeThreads.push_back(tid); }}template <class Impl>voidFullO3CPU<Impl>::deactivateThread(unsigned tid){ //Remove From Active List, if Active std::list<unsigned>::iterator thread_it = std::find(activeThreads.begin(), activeThreads.end(), tid); DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid); if (thread_it != activeThreads.end()) { DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n", tid); activeThreads.erase(thread_it); }}template <class Impl>voidFullO3CPU<Impl>::activateContext(int tid, int delay){ // Needs to set each stage to running as well. if (delay){ DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate " "on cycle %d\n", tid, curTick + ticks(delay)); scheduleActivateThreadEvent(tid, delay); } else { activateThread(tid); } if (lastActivatedCycle < curTick) { scheduleTickEvent(delay); // Be sure to signal that there's some activity so the CPU doesn't // deschedule itself. activityRec.activity(); fetch.wakeFromQuiesce(); lastActivatedCycle = curTick; _status = Running; }}template <class Impl>boolFullO3CPU<Impl>::deallocateContext(int tid, bool remove, int delay){ // Schedule removal of thread data from CPU if (delay){ DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate " "on cycle %d\n", tid, curTick + ticks(delay)); scheduleDeallocateContextEvent(tid, remove, delay); return false; } else { deactivateThread(tid); if (remove) removeThread(tid); return true; }}template <class Impl>voidFullO3CPU<Impl>::suspendContext(int tid){ DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); bool deallocated = deallocateContext(tid, false, 1); // If this was the last thread then unschedule the tick event. if (activeThreads.size() == 1 && !deallocated || activeThreads.size() == 0) unscheduleTickEvent(); _status = Idle;}template <class Impl>voidFullO3CPU<Impl>::haltContext(int tid){ //For now, this is the same as deallocate DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid); deallocateContext(tid, true, 1);}template <class Impl>voidFullO3CPU<Impl>::insertThread(unsigned tid){ DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU"); // Will change now that the PC and thread state is internal to the CPU // and not in the ThreadContext.#if FULL_SYSTEM ThreadContext *src_tc = system->threadContexts[tid];#else ThreadContext *src_tc = tcBase(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->copyFromTC(tid); //Set PC/NPC/NNPC setPC(src_tc->readPC(), tid); setNextPC(src_tc->readNextPC(), tid); setNextNPC(src_tc->readNextNPC(), tid); src_tc->setStatus(ThreadContext::Active); activateContext(tid,1); //Reset ROB/IQ/LSQ Entries commit.rob->resetEntries(); iew.resetEntries();}template <class Impl>voidFullO3CPU<Impl>::removeThread(unsigned tid){ DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid); // Copy Thread Data From RegFile // If thread is suspended, it might be re-allocated // this->copyToTC(tid); // @todo: 2-27-2008: Fix how we free up rename mappings // here to alleviate the case for double-freeing registers // in SMT workloads. // 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 = TheISA::NumIntRegs; freg < TheISA::NumFloatRegs; freg++) { PhysRegIndex phys_reg = renameMap[tid].lookup(freg); scoreboard.unsetReg(phys_reg); freeList.addReg(phys_reg); } // Squash Throughout Pipeline InstSeqNum squash_seq_num = commit.rob->readHeadInst(tid)->seqNum; fetch.squash(0, sizeof(TheISA::MachInst), 0, squash_seq_num, tid); decode.squash(tid); rename.squash(squash_seq_num, tid); iew.squash(tid); iew.ldstQueue.squash(squash_seq_num, tid); commit.rob->squash(squash_seq_num, tid); assert(iew.instQueue.getCount(tid) == 0); assert(iew.ldstQueue.getCount(tid) == 0); // Reset ROB/IQ/LSQ Entries // Commented out for now. This should be possible to do by // telling all the pipeline stages to drain first, and then // checking until the drain completes. Once the pipeline is // drained, call resetEntries(). - 10-09-06 ktlim/* if (activeThreads.size() >= 1) { commit.rob->resetEntries(); iew.resetEntries(); }*/}template <class Impl>voidFullO3CPU<Impl>::activateWhenReady(int tid){ DPRINTF(O3CPU,"[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(O3CPU,"[tid:%i] Suspending thread due to not enough " "Phys. Int. Regs.\n", tid); ready = false; } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { DPRINTF(O3CPU,"[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(O3CPU,"[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(O3CPU,"[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(O3CPU,"[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; //@todo: dont always add to waitlist //do waitlist cpuWaitList.push_back(tid); }}#if FULL_SYSTEMtemplate <class Impl>voidFullO3CPU<Impl>::updateMemPorts(){ // Update all ThreadContext's memory ports (Functional/Virtual // Ports) for (int i = 0; i < thread.size(); ++i) thread[i]->connectMemPorts();}#endiftemplate <class Impl>voidFullO3CPU<Impl>::serialize(std::ostream &os){ SimObject::State so_state = SimObject::getState(); SERIALIZE_ENUM(so_state); BaseCPU::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; for (int i = 0; i < thread.size(); i++) { nameOut(os, csprintf("%s.xc.%i", name(), i)); temp.copyTC(thread[i]->getTC()); temp.serialize(os); }}template <class Impl>voidFullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string §ion){ SimObject::State so_state; UNSERIALIZE_ENUM(so_state); BaseCPU::unserialize(cp, 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; for (int i = 0; i < thread.size(); i++) { temp.copyTC(thread[i]->getTC()); temp.unserialize(cp, csprintf("%s.xc.%i", section, i)); thread[i]->getTC()->copyArchRegs(temp.getTC()); }}template <class Impl>unsigned intFullO3CPU<Impl>::drain(Event *drain_event){ DPRINTF(O3CPU, "Switching out\n"); // If the CPU isn't doing anything, then return immediately. if (_status == Idle || _status == SwitchedOut) { return 0; } drainCount = 0; fetch.drain(); decode.drain(); rename.drain(); iew.drain(); commit.drain(); // Wake the CPU and record activity so everything can drain out if // the CPU was not able to immediately drain. if (getState() != SimObject::Drained) { // A bit of a hack...set the drainEvent after all the drain() // calls have been made, that way if all of the stages drain // immediately, the signalDrained() function knows not to call // process on the drain event. drainEvent = drain_event; wakeCPU(); activityRec.activity(); return 1; } else { return 0; }}template <class Impl>voidFullO3CPU<Impl>::resume(){ fetch.resume(); decode.resume(); rename.resume(); iew.resume(); commit.resume(); changeState(SimObject::Running); if (_status == SwitchedOut || _status == Idle) return;#if FULL_SYSTEM assert(system->getMemoryMode() == Enums::timing);#endif if (!tickEvent.scheduled()) tickEvent.schedule(nextCycle()); _status = Running;}template <class Impl>voidFullO3CPU<Impl>::signalDrained(){ if (++drainCount == NumStages) { if (tickEvent.scheduled()) tickEvent.squash(); changeState(SimObject::Drained); BaseCPU::switchOut(); if (drainEvent) { drainEvent->process(); drainEvent = NULL; } } assert(drainCount <= 5);}template <class Impl>voidFullO3CPU<Impl>::switchOut(){ fetch.switchOut(); rename.switchOut(); iew.switchOut(); commit.switchOut(); instList.clear(); while (!removeList.empty()) { removeList.pop(); } _status = SwitchedOut;#if USE_CHECKER if (checker) checker->switchOut();#endif if (tickEvent.scheduled()) tickEvent.squash();}template <class Impl>voidFullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU){ // Flush out any old data from the time buffers. for (int i = 0; i < timeBuffer.getSize(); ++i) { timeBuffer.advance(); fetchQueue.advance(); decodeQueue.advance(); renameQueue.advance(); iewQueue.advance(); } activityRec.reset(); BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort()); fetch.takeOverFrom(); decode.takeOverFrom(); rename.takeOverFrom(); iew.takeOverFrom(); commit.takeOverFrom(); assert(!tickEvent.scheduled()); // @todo: Figure out how to properly select the tid to put onto // the active threads list. int tid = 0; std::list<unsigned>::iterator isActive = std::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(O3CPU, "Adding Thread %i to active threads list\n", tid); activeThreads.push_back(tid); } // Set all statuses to active, schedule the CPU's tick event. // @todo: Fix up statuses so this is handled properly for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?