decode_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 758 行 · 第 1/2 页
HH
758 行
/* * Copyright (c) 2004, 2005, 2006 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Kevin T. Lim */#include "cpu/o3/decode.hh"template<class Impl>DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, Params *params) : cpu(_cpu), renameToDecodeDelay(params->renameToDecodeDelay), iewToDecodeDelay(params->iewToDecodeDelay), commitToDecodeDelay(params->commitToDecodeDelay), fetchToDecodeDelay(params->fetchToDecodeDelay), decodeWidth(params->decodeWidth), numThreads(params->numberOfThreads){ _status = Inactive; // Setup status, make sure stall signals are clear. for (int i = 0; i < numThreads; ++i) { decodeStatus[i] = Idle; stalls[i].rename = false; stalls[i].iew = false; stalls[i].commit = false; } // @todo: Make into a parameter skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth;}template <class Impl>std::stringDefaultDecode<Impl>::name() const{ return cpu->name() + ".decode";}template <class Impl>voidDefaultDecode<Impl>::regStats(){ decodeIdleCycles .name(name() + ".DECODE:IdleCycles") .desc("Number of cycles decode is idle") .prereq(decodeIdleCycles); decodeBlockedCycles .name(name() + ".DECODE:BlockedCycles") .desc("Number of cycles decode is blocked") .prereq(decodeBlockedCycles); decodeRunCycles .name(name() + ".DECODE:RunCycles") .desc("Number of cycles decode is running") .prereq(decodeRunCycles); decodeUnblockCycles .name(name() + ".DECODE:UnblockCycles") .desc("Number of cycles decode is unblocking") .prereq(decodeUnblockCycles); decodeSquashCycles .name(name() + ".DECODE:SquashCycles") .desc("Number of cycles decode is squashing") .prereq(decodeSquashCycles); decodeBranchResolved .name(name() + ".DECODE:BranchResolved") .desc("Number of times decode resolved a branch") .prereq(decodeBranchResolved); decodeBranchMispred .name(name() + ".DECODE:BranchMispred") .desc("Number of times decode detected a branch misprediction") .prereq(decodeBranchMispred); decodeControlMispred .name(name() + ".DECODE:ControlMispred") .desc("Number of times decode detected an instruction incorrectly" " predicted as a control") .prereq(decodeControlMispred); decodeDecodedInsts .name(name() + ".DECODE:DecodedInsts") .desc("Number of instructions handled by decode") .prereq(decodeDecodedInsts); decodeSquashedInsts .name(name() + ".DECODE:SquashedInsts") .desc("Number of squashed instructions handled by decode") .prereq(decodeSquashedInsts);}template<class Impl>voidDefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr){ timeBuffer = tb_ptr; // Setup wire to write information back to fetch. toFetch = timeBuffer->getWire(0); // Create wires to get information from proper places in time buffer. fromRename = timeBuffer->getWire(-renameToDecodeDelay); fromIEW = timeBuffer->getWire(-iewToDecodeDelay); fromCommit = timeBuffer->getWire(-commitToDecodeDelay);}template<class Impl>voidDefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr){ decodeQueue = dq_ptr; // Setup wire to write information to proper place in decode queue. toRename = decodeQueue->getWire(0);}template<class Impl>voidDefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr){ fetchQueue = fq_ptr; // Setup wire to read information from fetch queue. fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);}template<class Impl>voidDefaultDecode<Impl>::setActiveThreads(std::list<unsigned> *at_ptr){ activeThreads = at_ptr;}template <class Impl>boolDefaultDecode<Impl>::drain(){ // Decode is done draining at any time. cpu->signalDrained(); return true;}template <class Impl>voidDefaultDecode<Impl>::takeOverFrom(){ _status = Inactive; // Be sure to reset state and clear out any old instructions. for (int i = 0; i < numThreads; ++i) { decodeStatus[i] = Idle; stalls[i].rename = false; stalls[i].iew = false; stalls[i].commit = false; while (!insts[i].empty()) insts[i].pop(); while (!skidBuffer[i].empty()) skidBuffer[i].pop(); branchCount[i] = 0; } wroteToTimeBuffer = false;}template<class Impl>boolDefaultDecode<Impl>::checkStall(unsigned tid) const{ bool ret_val = false; if (stalls[tid].rename) { DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); ret_val = true; } else if (stalls[tid].iew) { DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); ret_val = true; } else if (stalls[tid].commit) { DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); ret_val = true; } return ret_val;}template<class Impl>inline boolDefaultDecode<Impl>::fetchInstsValid(){ return fromFetch->size > 0;}template<class Impl>boolDefaultDecode<Impl>::block(unsigned tid){ DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); // Add the current inputs to the skid buffer so they can be // reprocessed when this stage unblocks. skidInsert(tid); // If the decode status is blocked or unblocking then decode has not yet // signalled fetch to unblock. In that case, there is no need to tell // fetch to block. if (decodeStatus[tid] != Blocked) { // Set the status to Blocked. decodeStatus[tid] = Blocked; if (decodeStatus[tid] != Unblocking) { toFetch->decodeBlock[tid] = true; wroteToTimeBuffer = true; } return true; } return false;}template<class Impl>boolDefaultDecode<Impl>::unblock(unsigned tid){ // Decode is done unblocking only if the skid buffer is empty. if (skidBuffer[tid].empty()) { DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); toFetch->decodeUnblock[tid] = true; wroteToTimeBuffer = true; decodeStatus[tid] = Running; return true; } DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); return false;}template<class Impl>voidDefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid){ DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction " "detected at decode.\n", tid); // Send back mispredict information. toFetch->decodeInfo[tid].branchMispredict = true; toFetch->decodeInfo[tid].predIncorrect = true; toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; toFetch->decodeInfo[tid].squash = true; toFetch->decodeInfo[tid].nextPC = inst->branchTarget(); ///FIXME There needs to be a way to set the nextPC and nextNPC ///explicitly for ISAs with delay slots. toFetch->decodeInfo[tid].nextNPC = inst->branchTarget() + sizeof(TheISA::MachInst); toFetch->decodeInfo[tid].nextMicroPC = inst->readMicroPC();#if ISA_HAS_DELAY_SLOT toFetch->decodeInfo[tid].branchTaken = inst->readNextNPC() != (inst->readNextPC() + sizeof(TheISA::MachInst));#else toFetch->decodeInfo[tid].branchTaken = inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst));#endif InstSeqNum squash_seq_num = inst->seqNum; // Might have to tell fetch to unblock. if (decodeStatus[tid] == Blocked || decodeStatus[tid] == Unblocking) { toFetch->decodeUnblock[tid] = 1; } // Set status to squashing. decodeStatus[tid] = Squashing; for (int i=0; i<fromFetch->size; i++) { if (fromFetch->insts[i]->threadNumber == tid && fromFetch->insts[i]->seqNum > squash_seq_num) { fromFetch->insts[i]->setSquashed(); } } // Clear the instruction list and skid buffer in case they have any // insts in them. while (!insts[tid].empty()) { insts[tid].pop(); } while (!skidBuffer[tid].empty()) { skidBuffer[tid].pop(); } // Squash instructions up until this one cpu->removeInstsUntil(squash_seq_num, tid);}template<class Impl>unsignedDefaultDecode<Impl>::squash(unsigned tid){ DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); if (decodeStatus[tid] == Blocked || decodeStatus[tid] == Unblocking) {#if !FULL_SYSTEM // In syscall emulation, we can have both a block and a squash due // to a syscall in the same cycle. This would cause both signals to // be high. This shouldn't happen in full system. // @todo: Determine if this still happens. if (toFetch->decodeBlock[tid]) { toFetch->decodeBlock[tid] = 0; } else { toFetch->decodeUnblock[tid] = 1; }#else toFetch->decodeUnblock[tid] = 1;#endif } // Set status to squashing. decodeStatus[tid] = Squashing; // Go through incoming instructions from fetch and squash them. unsigned squash_count = 0; for (int i=0; i<fromFetch->size; i++) { if (fromFetch->insts[i]->threadNumber == tid) { fromFetch->insts[i]->setSquashed(); squash_count++; } } // Clear the instruction list and skid buffer in case they have any // insts in them. while (!insts[tid].empty()) { insts[tid].pop(); } while (!skidBuffer[tid].empty()) { skidBuffer[tid].pop(); } return squash_count;}template<class Impl>voidDefaultDecode<Impl>::skidInsert(unsigned tid){ DynInstPtr inst = NULL; while (!insts[tid].empty()) { inst = insts[tid].front(); insts[tid].pop(); assert(tid == inst->threadNumber); DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?