fetch_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,441 行 · 第 1/3 页
HH
1,441 行
{ if (_status == Active) { DPRINTF(Activity, "Deactivating stage.\n"); cpu->deactivateStage(O3CPU::FetchIdx); _status = Inactive; }}template <class Impl>boolDefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC, Addr &next_NPC, Addr &next_MicroPC){ // Do branch prediction check here. // A bit of a misnomer...next_PC is actually the current PC until // this function updates it. bool predict_taken; if (!inst->isControl()) { if (inst->isMicroop() && !inst->isLastMicroop()) { next_MicroPC++; } else { next_PC = next_NPC; next_NPC = next_NPC + instSize; next_MicroPC = 0; } inst->setPredTarg(next_PC, next_NPC, next_MicroPC); inst->setPredTaken(false); return false; } //Assume for now that all control flow is to a different macroop which //would reset the micro pc to 0. next_MicroPC = 0; int tid = inst->threadNumber; Addr pred_PC = next_PC; predict_taken = branchPred.predict(inst, pred_PC, tid);/* if (predict_taken) { DPRINTF(Fetch, "[tid:%i]: Branch predicted to be taken to %#x.\n", tid, pred_PC); } else { DPRINTF(Fetch, "[tid:%i]: Branch predicted to be not taken.\n", tid); }*/#if ISA_HAS_DELAY_SLOT next_PC = next_NPC; if (predict_taken) next_NPC = pred_PC; else next_NPC += instSize;#else if (predict_taken) next_PC = pred_PC; else next_PC += instSize; next_NPC = next_PC + instSize;#endif/* DPRINTF(Fetch, "[tid:%i]: Branch predicted to go to %#x and then %#x.\n", tid, next_PC, next_NPC);*/ inst->setPredTarg(next_PC, next_NPC, next_MicroPC); inst->setPredTaken(predict_taken); ++fetchedBranches; if (predict_taken) { ++predictedBranches; } return predict_taken;}template <class Impl>boolDefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid){ Fault fault = NoFault; //AlphaDep if (cacheBlocked) { DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, cache blocked\n", tid); return false; } else if (isSwitchedOut()) { DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, switched out\n", tid); return false; } else if (interruptPending && !(fetch_PC & 0x3)) { // Hold off fetch from getting new instructions when: // Cache is blocked, or // while an interrupt is pending and we're not in PAL mode, or // fetch is switched out. DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, interrupt pending\n", tid); return false; } // Align the fetch PC so it's at the start of a cache block. Addr block_PC = icacheBlockAlignPC(fetch_PC); // If we've already got the block, no need to try to fetch it again. if (cacheDataValid[tid] && block_PC == cacheDataPC[tid]) { return true; } // Setup the memReq to do a read of the first instruction's address. // Set the appropriate read size and flags as well. // Build request here. RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0, fetch_PC, cpu->readCpuId(), tid); memReq[tid] = mem_req; // Translate the instruction request. fault = cpu->translateInstReq(mem_req, cpu->thread[tid]); // In the case of faults, the fetch stage may need to stall and wait // for the ITB miss to be handled. // If translation was successful, attempt to read the first // instruction. if (fault == NoFault) {#if 0 if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) || memReq[tid]->isUncacheable()) { DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a " "misspeculating path)!", memReq[tid]->paddr); ret_fault = TheISA::genMachineCheckFault(); return false; }#endif // Build packet here. PacketPtr data_pkt = new Packet(mem_req, MemCmd::ReadReq, Packet::Broadcast); data_pkt->dataDynamicArray(new uint8_t[cacheBlkSize]); cacheDataPC[tid] = block_PC; cacheDataValid[tid] = false; DPRINTF(Fetch, "Fetch: Doing instruction read.\n"); fetchedCacheLines++; // Now do the timing access to see whether or not the instruction // exists within the cache. if (!icachePort->sendTiming(data_pkt)) { assert(retryPkt == NULL); assert(retryTid == -1); DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid); fetchStatus[tid] = IcacheWaitRetry; retryPkt = data_pkt; retryTid = tid; cacheBlocked = true; return false; } DPRINTF(Fetch, "[tid:%i]: Doing cache access.\n", tid); lastIcacheStall[tid] = curTick; DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache " "response.\n", tid); fetchStatus[tid] = IcacheWaitResponse; } else { delete mem_req; memReq[tid] = NULL; } ret_fault = fault; return true;}template <class Impl>inline voidDefaultFetch<Impl>::doSquash(const Addr &new_PC, const Addr &new_NPC, const Addr &new_microPC, unsigned tid){ DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x, NPC to: %#x.\n", tid, new_PC, new_NPC); PC[tid] = new_PC; nextPC[tid] = new_NPC; microPC[tid] = new_microPC; // Clear the icache miss if it's outstanding. if (fetchStatus[tid] == IcacheWaitResponse) { DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n", tid); memReq[tid] = NULL; } // Get rid of the retrying packet if it was from this thread. if (retryTid == tid) { assert(cacheBlocked); if (retryPkt) { delete retryPkt->req; delete retryPkt; } retryPkt = NULL; retryTid = -1; } fetchStatus[tid] = Squashing; ++fetchSquashCycles;}template<class Impl>voidDefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, const Addr &new_NPC, const Addr &new_MicroPC, const InstSeqNum &seq_num, unsigned tid){ DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid); doSquash(new_PC, new_NPC, new_MicroPC, tid); // Tell the CPU to remove any instructions that are in flight between // fetch and decode. cpu->removeInstsUntil(seq_num, tid);}template<class Impl>boolDefaultFetch<Impl>::checkStall(unsigned tid) const{ bool ret_val = false; if (cpu->contextSwitch) { DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid); ret_val = true; } else if (stalls[tid].decode) { DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid); ret_val = true; } else if (stalls[tid].rename) { DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid); ret_val = true; } else if (stalls[tid].iew) { DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid); ret_val = true; } else if (stalls[tid].commit) { DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid); ret_val = true; } return ret_val;}template<class Impl>typename DefaultFetch<Impl>::FetchStatusDefaultFetch<Impl>::updateFetchStatus(){ //Check Running std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); while (threads != end) { unsigned tid = *threads++; if (fetchStatus[tid] == Running || fetchStatus[tid] == Squashing || fetchStatus[tid] == IcacheAccessComplete) { if (_status == Inactive) { DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid); if (fetchStatus[tid] == IcacheAccessComplete) { DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache" "completion\n",tid); } cpu->activateStage(O3CPU::FetchIdx); } return Active; } } // Stage is switching from active to inactive, notify CPU of it. if (_status == Active) { DPRINTF(Activity, "Deactivating stage.\n"); cpu->deactivateStage(O3CPU::FetchIdx); } return Inactive;}template <class Impl>voidDefaultFetch<Impl>::squash(const Addr &new_PC, const Addr &new_NPC, const Addr &new_MicroPC, const InstSeqNum &seq_num, unsigned tid){ DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid); doSquash(new_PC, new_NPC, new_MicroPC, tid); // Tell the CPU to remove any instructions that are not in the ROB. cpu->removeInstsNotInROB(tid);}template <class Impl>voidDefaultFetch<Impl>::tick(){ std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); bool status_change = false; wroteToTimeBuffer = false; while (threads != end) { unsigned tid = *threads++; // Check the signals for each thread to determine the proper status // for each thread. bool updated_status = checkSignalsAndUpdate(tid); status_change = status_change || updated_status; } DPRINTF(Fetch, "Running stage.\n"); // Reset the number of the instruction we're fetching. numInst = 0;#if FULL_SYSTEM if (fromCommit->commitInfo[0].interruptPending) { interruptPending = true; } if (fromCommit->commitInfo[0].clearInterrupt) { interruptPending = false; }#endif for (threadFetched = 0; threadFetched < numFetchingThreads; threadFetched++) { // Fetch each of the actively fetching threads. fetch(status_change); } // Record number of instructions fetched this cycle for distribution. fetchNisnDist.sample(numInst); if (status_change) { // Change the fetch stage status if there was a status change. _status = updateFetchStatus(); } // If there was activity this cycle, inform the CPU of it. if (wroteToTimeBuffer || cpu->contextSwitch) { DPRINTF(Activity, "Activity this cycle.\n"); cpu->activityThisCycle(); }}template <class Impl>boolDefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid){ // Update the per thread stall statuses. if (fromDecode->decodeBlock[tid]) { stalls[tid].decode = true; } if (fromDecode->decodeUnblock[tid]) { assert(stalls[tid].decode); assert(!fromDecode->decodeBlock[tid]); stalls[tid].decode = false; } if (fromRename->renameBlock[tid]) { stalls[tid].rename = true; } if (fromRename->renameUnblock[tid]) { assert(stalls[tid].rename); assert(!fromRename->renameBlock[tid]); stalls[tid].rename = false; } if (fromIEW->iewBlock[tid]) { stalls[tid].iew = true; } if (fromIEW->iewUnblock[tid]) { assert(stalls[tid].iew); assert(!fromIEW->iewBlock[tid]); stalls[tid].iew = false; } if (fromCommit->commitBlock[tid]) { stalls[tid].commit = true; } if (fromCommit->commitUnblock[tid]) { assert(stalls[tid].commit); assert(!fromCommit->commitBlock[tid]); stalls[tid].commit = false; } // Check squash signals from commit. if (fromCommit->commitInfo[tid].squash) { DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " "from commit.\n",tid); // In any case, squash. squash(fromCommit->commitInfo[tid].nextPC, fromCommit->commitInfo[tid].nextNPC, fromCommit->commitInfo[tid].nextMicroPC, fromCommit->commitInfo[tid].doneSeqNum, tid); // Also check if there's a mispredict that happened. if (fromCommit->commitInfo[tid].branchMispredict) { branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, fromCommit->commitInfo[tid].nextPC, fromCommit->commitInfo[tid].branchTaken, tid); } else { branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, tid); } return true; } else if (fromCommit->commitInfo[tid].doneSeqNum) { // Update the branch predictor if it wasn't a squashed instruction // that was broadcasted. branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid); } // Check ROB squash signals from commit. if (fromCommit->commitInfo[tid].robSquashing) { DPRINTF(Fetch, "[tid:%u]: ROB is still squashing.\n", tid); // Continue to squash. fetchStatus[tid] = Squashing; return true; } // Check squash signals from decode. if (fromDecode->decodeInfo[tid].squash) { DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " "from decode.\n",tid); // Update the branch predictor. if (fromDecode->decodeInfo[tid].branchMispredict) { branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, fromDecode->decodeInfo[tid].nextPC, fromDecode->decodeInfo[tid].branchTaken, tid); } else { branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, tid); } if (fetchStatus[tid] != Squashing) { DPRINTF(Fetch, "Squashing from decode with PC = %#x, NPC = %#x\n", fromDecode->decodeInfo[tid].nextPC, fromDecode->decodeInfo[tid].nextNPC); // Squash unless we're already squashing squashFromDecode(fromDecode->decodeInfo[tid].nextPC, fromDecode->decodeInfo[tid].nextNPC, fromDecode->decodeInfo[tid].nextMicroPC, fromDecode->decodeInfo[tid].doneSeqNum, tid); return true; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?