commit_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,375 行 · 第 1/3 页
HH
1,375 行
TrapEvent *trap = new TrapEvent(this, tid); trap->schedule(curTick + trapLatency); trapInFlight[tid] = true;}template <class Impl>voidDefaultCommit<Impl>::generateTCEvent(unsigned tid){ assert(!trapInFlight[tid]); DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid); tcSquash[tid] = true;}template <class Impl>voidDefaultCommit<Impl>::squashAll(unsigned tid){ // If we want to include the squashing instruction in the squash, // then use one older sequence number. // Hopefully this doesn't mess things up. Basically I want to squash // all instructions of this thread. InstSeqNum squashed_inst = rob->isEmpty() ? 0 : rob->readHeadInst(tid)->seqNum - 1; // All younger instructions will be squashed. Set the sequence // number as the youngest instruction in the ROB (0 in this case. // Hopefully nothing breaks.) youngestSeqNum[tid] = 0; rob->squash(squashed_inst, tid); changedROBNumEntries[tid] = true; // Send back the sequence number of the squashed instruction. toIEW->commitInfo[tid].doneSeqNum = squashed_inst; // Send back the squash signal to tell stages that they should // squash. toIEW->commitInfo[tid].squash = true; // Send back the rob squashing signal so other stages know that // the ROB is in the process of squashing. toIEW->commitInfo[tid].robSquashing = true; toIEW->commitInfo[tid].branchMispredict = false; toIEW->commitInfo[tid].nextPC = PC[tid]; toIEW->commitInfo[tid].nextNPC = nextPC[tid]; toIEW->commitInfo[tid].nextMicroPC = nextMicroPC[tid];}template <class Impl>voidDefaultCommit<Impl>::squashFromTrap(unsigned tid){ squashAll(tid); DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]); thread[tid]->trapPending = false; thread[tid]->inSyscall = false; trapInFlight[tid] = false; trapSquash[tid] = false; commitStatus[tid] = ROBSquashing; cpu->activityThisCycle();}template <class Impl>voidDefaultCommit<Impl>::squashFromTC(unsigned tid){ squashAll(tid); DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]); thread[tid]->inSyscall = false; assert(!thread[tid]->trapPending); commitStatus[tid] = ROBSquashing; cpu->activityThisCycle(); tcSquash[tid] = false;}template <class Impl>voidDefaultCommit<Impl>::tick(){ wroteToTimeBuffer = false; _nextStatus = Inactive; if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { cpu->signalDrained(); drainPending = false; return; } if (activeThreads->empty()) return; std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); // Check if any of the threads are done squashing. Change the // status if they are done. while (threads != end) { unsigned tid = *threads++; // Clear the bit saying if the thread has committed stores // this cycle. committedStores[tid] = false; if (commitStatus[tid] == ROBSquashing) { if (rob->isDoneSquashing(tid)) { commitStatus[tid] = Running; } else { DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" " insts this cycle.\n", tid); rob->doSquash(tid); toIEW->commitInfo[tid].robSquashing = true; wroteToTimeBuffer = true; } } } commit(); markCompletedInsts(); threads = activeThreads->begin(); while (threads != end) { unsigned tid = *threads++; if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { // The ROB has more instructions it can commit. Its next status // will be active. _nextStatus = Active; DynInstPtr inst = rob->readHeadInst(tid); DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of" " ROB and ready to commit\n", tid, inst->seqNum, inst->readPC()); } else if (!rob->isEmpty(tid)) { DynInstPtr inst = rob->readHeadInst(tid); DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " "%#x is head of ROB and not ready\n", tid, inst->seqNum, inst->readPC()); } DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", tid, rob->countInsts(tid), rob->numFreeEntries(tid)); } if (wroteToTimeBuffer) { DPRINTF(Activity, "Activity This Cycle.\n"); cpu->activityThisCycle(); } updateStatus();}#if FULL_SYSTEMtemplate <class Impl>voidDefaultCommit<Impl>::handleInterrupt(){ if (interrupt != NoFault) { // Wait until the ROB is empty and all stores have drained in // order to enter the interrupt. if (rob->isEmpty() && !iewStage->hasStoresToWB()) { // Squash or record that I need to squash this cycle if // an interrupt needed to be handled. DPRINTF(Commit, "Interrupt detected.\n"); // Clear the interrupt now that it's going to be handled toIEW->commitInfo[0].clearInterrupt = true; assert(!thread[0]->inSyscall); thread[0]->inSyscall = true; // CPU will handle interrupt. cpu->processInterrupts(interrupt); thread[0]->inSyscall = false; commitStatus[0] = TrapPending; // Generate trap squash event. generateTrapEvent(0); interrupt = NoFault; } else { DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); } } else if (commitStatus[0] != TrapPending && cpu->check_interrupts(cpu->tcBase(0)) && !trapSquash[0] && !tcSquash[0]) { // Process interrupts if interrupts are enabled, not in PAL // mode, and no other traps or external squashes are currently // pending. // @todo: Allow other threads to handle interrupts. // Get any interrupt that happened interrupt = cpu->getInterrupts(); if (interrupt != NoFault) { // Tell fetch that there is an interrupt pending. This // will make fetch wait until it sees a non PAL-mode PC, // at which point it stops fetching instructions. toIEW->commitInfo[0].interruptPending = true; } }}#endif // FULL_SYSTEMtemplate <class Impl>voidDefaultCommit<Impl>::commit(){#if FULL_SYSTEM // Check for any interrupt, and start processing it. Or if we // have an outstanding interrupt and are at a point when it is // valid to take an interrupt, process it. if (cpu->check_interrupts(cpu->tcBase(0))) { handleInterrupt(); }#endif // FULL_SYSTEM //////////////////////////////////// // Check for any possible squashes, handle them first //////////////////////////////////// std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); while (threads != end) { unsigned tid = *threads++; // Not sure which one takes priority. I think if we have // both, that's a bad sign. if (trapSquash[tid] == true) { assert(!tcSquash[tid]); squashFromTrap(tid); } else if (tcSquash[tid] == true) { assert(commitStatus[tid] != TrapPending); squashFromTC(tid); } // Squashed sequence number must be older than youngest valid // instruction in the ROB. This prevents squashes from younger // instructions overriding squashes from older instructions. if (fromIEW->squash[tid] && commitStatus[tid] != TrapPending && fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", tid, fromIEW->mispredPC[tid], fromIEW->squashedSeqNum[tid]); DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", tid, fromIEW->nextPC[tid]); commitStatus[tid] = ROBSquashing; // If we want to include the squashing instruction in the squash, // then use one older sequence number. InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; if (fromIEW->includeSquashInst[tid] == true) { squashed_inst--; } // All younger instructions will be squashed. Set the sequence // number as the youngest instruction in the ROB. youngestSeqNum[tid] = squashed_inst; rob->squash(squashed_inst, tid); changedROBNumEntries[tid] = true; toIEW->commitInfo[tid].doneSeqNum = squashed_inst; toIEW->commitInfo[tid].squash = true; // Send back the rob squashing signal so other stages know that // the ROB is in the process of squashing. toIEW->commitInfo[tid].robSquashing = true; toIEW->commitInfo[tid].branchMispredict = fromIEW->branchMispredict[tid]; toIEW->commitInfo[tid].branchTaken = fromIEW->branchTaken[tid]; toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid]; toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid]; toIEW->commitInfo[tid].nextMicroPC = fromIEW->nextMicroPC[tid]; toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; if (toIEW->commitInfo[tid].branchMispredict) { ++branchMispredicts; } } } setNextStatus(); if (squashCounter != numThreads) { // If we're not currently squashing, then get instructions. getInsts(); // Try to commit any instructions. commitInsts(); } //Check for any activity threads = activeThreads->begin(); while (threads != end) { unsigned tid = *threads++; if (changedROBNumEntries[tid]) { toIEW->commitInfo[tid].usedROB = true; toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); wroteToTimeBuffer = true; changedROBNumEntries[tid] = false; if (rob->isEmpty(tid)) checkEmptyROB[tid] = true; } // ROB is only considered "empty" for previous stages if: a) // ROB is empty, b) there are no outstanding stores, c) IEW // stage has received any information regarding stores that // committed. // c) is checked by making sure to not consider the ROB empty // on the same cycle as when stores have been committed. // @todo: Make this handle multi-cycle communication between // commit and IEW. if (checkEmptyROB[tid] && rob->isEmpty(tid) && !iewStage->hasStoresToWB() && !committedStores[tid]) { checkEmptyROB[tid] = false; toIEW->commitInfo[tid].usedROB = true; toIEW->commitInfo[tid].emptyROB = true; toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); wroteToTimeBuffer = true; } }}template <class Impl>voidDefaultCommit<Impl>::commitInsts(){ //////////////////////////////////// // Handle commit // Note that commit will be handled prior to putting new // instructions in the ROB so that the ROB only tries to commit // instructions it has in this current cycle, and not instructions // it is writing in during this cycle. Can't commit and squash // things at the same time... //////////////////////////////////// DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); unsigned num_committed = 0; DynInstPtr head_inst; // Commit as many instructions as possible until the commit bandwidth // limit is reached, or it becomes impossible to commit any more. while (num_committed < commitWidth) { int commit_thread = getCommittingThread(); if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) break; head_inst = rob->readHeadInst(commit_thread); int tid = head_inst->threadNumber; assert(tid == commit_thread); DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", head_inst->seqNum, tid); // If the head instruction is squashed, it is ready to retire // (be removed from the ROB) at any time. if (head_inst->isSquashed()) { DPRINTF(Commit, "Retiring squashed instruction from " "ROB.\n"); rob->retireHead(commit_thread); ++commitSquashedInsts; // Record that the number of ROB entries has changed. changedROBNumEntries[tid] = true; } else { PC[tid] = head_inst->readPC(); nextPC[tid] = head_inst->readNextPC(); nextNPC[tid] = head_inst->readNextNPC(); nextMicroPC[tid] = head_inst->readNextMicroPC(); // Increment the total number of non-speculative instructions // executed. // Hack for now: it really shouldn't happen until after the // commit is deemed to be successful, but this count is needed // for syscalls. thread[tid]->funcExeInst++; // Try to commit the head instruction. bool commit_success = commitHead(head_inst, num_committed); if (commit_success) { ++num_committed; changedROBNumEntries[tid] = true; // Set the doneSeqNum to the youngest committed instruction. toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; ++commitCommittedInsts; // To match the old model, don't count nops and instruction // prefetches towards the total commit count. if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { cpu->instDone(tid); } PC[tid] = nextPC[tid]; nextPC[tid] = nextNPC[tid]; nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst); microPC[tid] = nextMicroPC[tid]; nextMicroPC[tid] = microPC[tid] + 1; int count = 0; Addr oldpc; // Debug statement. Checks to make sure we're not // currently updating state while handling PC events. assert(!thread[tid]->inSyscall && !thread[tid]->trapPending); do {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?