decode_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 758 行 · 第 1/2 页
HH
758 行
inst->seqNum, inst->readPC(), inst->threadNumber); skidBuffer[tid].push(inst); } // @todo: Eventually need to enforce this by not letting a thread // fetch past its skidbuffer assert(skidBuffer[tid].size() <= skidBufferMax);}template<class Impl>boolDefaultDecode<Impl>::skidsEmpty(){ std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); while (threads != end) { unsigned tid = *threads++; if (!skidBuffer[tid].empty()) return false; } return true;}template<class Impl>voidDefaultDecode<Impl>::updateStatus(){ bool any_unblocking = false; std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); while (threads != end) { unsigned tid = *threads++; if (decodeStatus[tid] == Unblocking) { any_unblocking = true; break; } } // Decode will have activity if it's unblocking. if (any_unblocking) { if (_status == Inactive) { _status = Active; DPRINTF(Activity, "Activating stage.\n"); cpu->activateStage(O3CPU::DecodeIdx); } } else { // If it's not unblocking, then decode will not have any internal // activity. Switch it to inactive. if (_status == Active) { _status = Inactive; DPRINTF(Activity, "Deactivating stage.\n"); cpu->deactivateStage(O3CPU::DecodeIdx); } }}template <class Impl>voidDefaultDecode<Impl>::sortInsts(){ int insts_from_fetch = fromFetch->size;#ifdef DEBUG for (int i=0; i < numThreads; i++) assert(insts[i].empty());#endif for (int i = 0; i < insts_from_fetch; ++i) { insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); }}template<class Impl>voidDefaultDecode<Impl>::readStallSignals(unsigned tid){ if (fromRename->renameBlock[tid]) { stalls[tid].rename = true; } if (fromRename->renameUnblock[tid]) { assert(stalls[tid].rename); stalls[tid].rename = false; } if (fromIEW->iewBlock[tid]) { stalls[tid].iew = true; } if (fromIEW->iewUnblock[tid]) { assert(stalls[tid].iew); stalls[tid].iew = false; } if (fromCommit->commitBlock[tid]) { stalls[tid].commit = true; } if (fromCommit->commitUnblock[tid]) { assert(stalls[tid].commit); stalls[tid].commit = false; }}template <class Impl>boolDefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid){ // Check if there's a squash signal, squash if there is. // Check stall signals, block if necessary. // If status was blocked // Check if stall conditions have passed // if so then go to unblocking // If status was Squashing // check if squashing is not high. Switch to running this cycle. // Update the per thread stall statuses. readStallSignals(tid); // Check squash signals from commit. if (fromCommit->commitInfo[tid].squash) { DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " "from commit.\n", tid); squash(tid); return true; } // Check ROB squash signals from commit. if (fromCommit->commitInfo[tid].robSquashing) { DPRINTF(Decode, "[tid:%u]: ROB is still squashing.\n", tid); // Continue to squash. decodeStatus[tid] = Squashing; return true; } if (checkStall(tid)) { return block(tid); } if (decodeStatus[tid] == Blocked) { DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", tid); decodeStatus[tid] = Unblocking; unblock(tid); return true; } if (decodeStatus[tid] == Squashing) { // Switch status to running if decode isn't being told to block or // squash this cycle. DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", tid); decodeStatus[tid] = Running; return false; } // If we've reached this point, we have not gotten any signals that // cause decode to change its status. Decode remains the same as before. return false;}template<class Impl>voidDefaultDecode<Impl>::tick(){ wroteToTimeBuffer = false; bool status_change = false; toRenameIndex = 0; std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); sortInsts(); //Check stall and squash signals. while (threads != end) { unsigned tid = *threads++; DPRINTF(Decode,"Processing [tid:%i]\n",tid); status_change = checkSignalsAndUpdate(tid) || status_change; decode(status_change, tid); } if (status_change) { updateStatus(); } if (wroteToTimeBuffer) { DPRINTF(Activity, "Activity this cycle.\n"); cpu->activityThisCycle(); }}template<class Impl>voidDefaultDecode<Impl>::decode(bool &status_change, unsigned tid){ // If status is Running or idle, // call decodeInsts() // If status is Unblocking, // buffer any instructions coming from fetch // continue trying to empty skid buffer // check if stall conditions have passed if (decodeStatus[tid] == Blocked) { ++decodeBlockedCycles; } else if (decodeStatus[tid] == Squashing) { ++decodeSquashCycles; } // Decode should try to decode as many instructions as its bandwidth // will allow, as long as it is not currently blocked. if (decodeStatus[tid] == Running || decodeStatus[tid] == Idle) { DPRINTF(Decode, "[tid:%u]: Not blocked, so attempting to run " "stage.\n",tid); decodeInsts(tid); } else if (decodeStatus[tid] == Unblocking) { // Make sure that the skid buffer has something in it if the // status is unblocking. assert(!skidsEmpty()); // If the status was unblocking, then instructions from the skid // buffer were used. Remove those instructions and handle // the rest of unblocking. decodeInsts(tid); if (fetchInstsValid()) { // Add the current inputs to the skid buffer so they can be // reprocessed when this stage unblocks. skidInsert(tid); } status_change = unblock(tid) || status_change; }}template <class Impl>voidDefaultDecode<Impl>::decodeInsts(unsigned tid){ // Instructions can come either from the skid buffer or the list of // instructions coming from fetch, depending on decode's status. int insts_available = decodeStatus[tid] == Unblocking ? skidBuffer[tid].size() : insts[tid].size(); if (insts_available == 0) { DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" " early.\n",tid); // Should I change the status to idle? ++decodeIdleCycles; return; } else if (decodeStatus[tid] == Unblocking) { DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " "buffer.\n",tid); ++decodeUnblockCycles; } else if (decodeStatus[tid] == Running) { ++decodeRunCycles; } DynInstPtr inst; std::queue<DynInstPtr> &insts_to_decode = decodeStatus[tid] == Unblocking ? skidBuffer[tid] : insts[tid]; DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); while (insts_available > 0 && toRenameIndex < decodeWidth) { assert(!insts_to_decode.empty()); inst = insts_to_decode.front(); insts_to_decode.pop(); DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " "PC %#x\n", tid, inst->seqNum, inst->readPC()); if (inst->isSquashed()) { DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is " "squashed, skipping.\n", tid, inst->seqNum, inst->readPC()); ++decodeSquashedInsts; --insts_available; continue; } // Also check if instructions have no source registers. Mark // them as ready to issue at any time. Not sure if this check // should exist here or at a later stage; however it doesn't matter // too much for function correctness. if (inst->numSrcRegs() == 0) { inst->setCanIssue(); } // This current instruction is valid, so add it into the decode // queue. The next instruction may not be valid, so check to // see if branches were predicted correctly. toRename->insts[toRenameIndex] = inst; ++(toRename->size); ++toRenameIndex; ++decodeDecodedInsts; --insts_available; // Ensure that if it was predicted as a branch, it really is a // branch. if (inst->readPredTaken() && !inst->isControl()) { DPRINTF(Decode, "PredPC : %#x != NextPC: %#x\n", inst->readPredPC(), inst->readNextPC() + 4); panic("Instruction predicted as a branch!"); ++decodeControlMispred; // Might want to set some sort of boolean and just do // a check at the end squash(inst, inst->threadNumber); break; } // Go ahead and compute any PC-relative branches. if (inst->isDirectCtrl() && inst->isUncondCtrl()) { ++decodeBranchResolved; if (inst->branchTarget() != inst->readPredPC()) { ++decodeBranchMispred; // Might want to set some sort of boolean and just do // a check at the end squash(inst, inst->threadNumber); Addr target = inst->branchTarget(); //The micro pc after an instruction level branch should be 0 inst->setPredTarg(target, target + sizeof(TheISA::MachInst), 0); break; } } } // If we didn't process all instructions, then we will need to block // and put all those instructions into the skid buffer. if (!insts_to_decode.empty()) { block(tid); } // Record that decode has written to the time buffer for activity // tracking. if (toRenameIndex) { wroteToTimeBuffer = true; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?