decode_impl.hh revision 3093:b09c33e66bce
112952Sgabeblack@google.com/* 212952Sgabeblack@google.com * Copyright (c) 2004-2006 The Regents of The University of Michigan 312952Sgabeblack@google.com * All rights reserved. 412952Sgabeblack@google.com * 512952Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 612952Sgabeblack@google.com * modification, are permitted provided that the following conditions are 712952Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 812952Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 912952Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1012952Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1112952Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1212952Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1312952Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1412952Sgabeblack@google.com * this software without specific prior written permission. 1512952Sgabeblack@google.com * 1612952Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712952Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812952Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912952Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012952Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112952Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212952Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312952Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412952Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512952Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612952Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712952Sgabeblack@google.com * 2812952Sgabeblack@google.com * Authors: Kevin Lim 2912952Sgabeblack@google.com */ 3012952Sgabeblack@google.com 3112957Sgabeblack@google.com#include "cpu/o3/decode.hh" 3212957Sgabeblack@google.com 3312957Sgabeblack@google.comtemplate<class Impl> 3412953Sgabeblack@google.comDefaultDecode<Impl>::DefaultDecode(Params *params) 3513102Sgabeblack@google.com : renameToDecodeDelay(params->renameToDecodeDelay), 3612998Sgabeblack@google.com iewToDecodeDelay(params->iewToDecodeDelay), 3712998Sgabeblack@google.com commitToDecodeDelay(params->commitToDecodeDelay), 3812952Sgabeblack@google.com fetchToDecodeDelay(params->fetchToDecodeDelay), 3912952Sgabeblack@google.com decodeWidth(params->decodeWidth), 4012952Sgabeblack@google.com numThreads(params->numberOfThreads) 4112952Sgabeblack@google.com{ 4212957Sgabeblack@google.com _status = Inactive; 4313063Sgabeblack@google.com 4412957Sgabeblack@google.com // Setup status, make sure stall signals are clear. 4513063Sgabeblack@google.com for (int i = 0; i < numThreads; ++i) { 4612957Sgabeblack@google.com decodeStatus[i] = Idle; 4712957Sgabeblack@google.com 4812957Sgabeblack@google.com stalls[i].rename = false; 4912957Sgabeblack@google.com stalls[i].iew = false; 5012957Sgabeblack@google.com stalls[i].commit = false; 5112962Sgabeblack@google.com 5212962Sgabeblack@google.com squashAfterDelaySlot[i] = false; 5312962Sgabeblack@google.com } 5412962Sgabeblack@google.com 5512962Sgabeblack@google.com // @todo: Make into a parameter 5612962Sgabeblack@google.com skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; 5712962Sgabeblack@google.com} 5812957Sgabeblack@google.com 5912957Sgabeblack@google.comtemplate <class Impl> 6012957Sgabeblack@google.comstd::string 6112957Sgabeblack@google.comDefaultDecode<Impl>::name() const 6212957Sgabeblack@google.com{ 6312957Sgabeblack@google.com return cpu->name() + ".decode"; 6412957Sgabeblack@google.com} 6512957Sgabeblack@google.com 6612957Sgabeblack@google.comtemplate <class Impl> 6712957Sgabeblack@google.comvoid 6812957Sgabeblack@google.comDefaultDecode<Impl>::regStats() 6912957Sgabeblack@google.com{ 7012957Sgabeblack@google.com decodeIdleCycles 7112957Sgabeblack@google.com .name(name() + ".DECODE:IdleCycles") 7212957Sgabeblack@google.com .desc("Number of cycles decode is idle") 7312957Sgabeblack@google.com .prereq(decodeIdleCycles); 7412957Sgabeblack@google.com decodeBlockedCycles 7512957Sgabeblack@google.com .name(name() + ".DECODE:BlockedCycles") 7612957Sgabeblack@google.com .desc("Number of cycles decode is blocked") 7712957Sgabeblack@google.com .prereq(decodeBlockedCycles); 7812957Sgabeblack@google.com decodeRunCycles 7912957Sgabeblack@google.com .name(name() + ".DECODE:RunCycles") 8012957Sgabeblack@google.com .desc("Number of cycles decode is running") 8112957Sgabeblack@google.com .prereq(decodeRunCycles); 8212957Sgabeblack@google.com decodeUnblockCycles 8312957Sgabeblack@google.com .name(name() + ".DECODE:UnblockCycles") 8412957Sgabeblack@google.com .desc("Number of cycles decode is unblocking") 8512957Sgabeblack@google.com .prereq(decodeUnblockCycles); 8612957Sgabeblack@google.com decodeSquashCycles 8712957Sgabeblack@google.com .name(name() + ".DECODE:SquashCycles") 8812957Sgabeblack@google.com .desc("Number of cycles decode is squashing") 8912957Sgabeblack@google.com .prereq(decodeSquashCycles); 9012957Sgabeblack@google.com decodeBranchResolved 9112959Sgabeblack@google.com .name(name() + ".DECODE:BranchResolved") 9212957Sgabeblack@google.com .desc("Number of times decode resolved a branch") 9312957Sgabeblack@google.com .prereq(decodeBranchResolved); 9412957Sgabeblack@google.com decodeBranchMispred 9512957Sgabeblack@google.com .name(name() + ".DECODE:BranchMispred") 9612957Sgabeblack@google.com .desc("Number of times decode detected a branch misprediction") 9712957Sgabeblack@google.com .prereq(decodeBranchMispred); 9812957Sgabeblack@google.com decodeControlMispred 9912957Sgabeblack@google.com .name(name() + ".DECODE:ControlMispred") 10012957Sgabeblack@google.com .desc("Number of times decode detected an instruction incorrectly" 10112957Sgabeblack@google.com " predicted as a control") 10212957Sgabeblack@google.com .prereq(decodeControlMispred); 10312957Sgabeblack@google.com decodeDecodedInsts 10412957Sgabeblack@google.com .name(name() + ".DECODE:DecodedInsts") 10512957Sgabeblack@google.com .desc("Number of instructions handled by decode") 10612957Sgabeblack@google.com .prereq(decodeDecodedInsts); 10712957Sgabeblack@google.com decodeSquashedInsts 10813075Sgabeblack@google.com .name(name() + ".DECODE:SquashedInsts") 10913075Sgabeblack@google.com .desc("Number of squashed instructions handled by decode") 11013075Sgabeblack@google.com .prereq(decodeSquashedInsts); 11113075Sgabeblack@google.com} 11213075Sgabeblack@google.com 11313075Sgabeblack@google.comtemplate<class Impl> 11413075Sgabeblack@google.comvoid 11513075Sgabeblack@google.comDefaultDecode<Impl>::setCPU(O3CPU *cpu_ptr) 11613075Sgabeblack@google.com{ 11713075Sgabeblack@google.com DPRINTF(Decode, "Setting CPU pointer.\n"); 11813075Sgabeblack@google.com cpu = cpu_ptr; 11913075Sgabeblack@google.com} 12012957Sgabeblack@google.com 12112952Sgabeblack@google.comtemplate<class Impl> 12212952Sgabeblack@google.comvoid 12312952Sgabeblack@google.comDefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 12412995Sgabeblack@google.com{ 12512952Sgabeblack@google.com DPRINTF(Decode, "Setting time buffer pointer.\n"); 12612952Sgabeblack@google.com timeBuffer = tb_ptr; 12712952Sgabeblack@google.com 12812952Sgabeblack@google.com // Setup wire to write information back to fetch. 12912952Sgabeblack@google.com toFetch = timeBuffer->getWire(0); 13012995Sgabeblack@google.com 13112952Sgabeblack@google.com // Create wires to get information from proper places in time buffer. 13212952Sgabeblack@google.com fromRename = timeBuffer->getWire(-renameToDecodeDelay); 13312952Sgabeblack@google.com fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 13412952Sgabeblack@google.com fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 13512952Sgabeblack@google.com} 13612952Sgabeblack@google.com 13712952Sgabeblack@google.comtemplate<class Impl> 13812952Sgabeblack@google.comvoid 13912952Sgabeblack@google.comDefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 14012952Sgabeblack@google.com{ 14112952Sgabeblack@google.com DPRINTF(Decode, "Setting decode queue pointer.\n"); 14212952Sgabeblack@google.com decodeQueue = dq_ptr; 14312952Sgabeblack@google.com 14412952Sgabeblack@google.com // Setup wire to write information to proper place in decode queue. 14512952Sgabeblack@google.com toRename = decodeQueue->getWire(0); 14612952Sgabeblack@google.com} 14712952Sgabeblack@google.com 14812952Sgabeblack@google.comtemplate<class Impl> 14912952Sgabeblack@google.comvoid 15012952Sgabeblack@google.comDefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 15112952Sgabeblack@google.com{ 15212952Sgabeblack@google.com DPRINTF(Decode, "Setting fetch queue pointer.\n"); 15312952Sgabeblack@google.com fetchQueue = fq_ptr; 15412952Sgabeblack@google.com 15512952Sgabeblack@google.com // Setup wire to read information from fetch queue. 15612952Sgabeblack@google.com fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 15712952Sgabeblack@google.com} 15812952Sgabeblack@google.com 15912952Sgabeblack@google.comtemplate<class Impl> 16012952Sgabeblack@google.comvoid 16112952Sgabeblack@google.comDefaultDecode<Impl>::setActiveThreads(std::list<unsigned> *at_ptr) 16212952Sgabeblack@google.com{ 16313133Sgabeblack@google.com DPRINTF(Decode, "Setting active threads list pointer.\n"); 16412952Sgabeblack@google.com activeThreads = at_ptr; 16513133Sgabeblack@google.com} 16613133Sgabeblack@google.com 16713133Sgabeblack@google.comtemplate <class Impl> 16813133Sgabeblack@google.combool 16913133Sgabeblack@google.comDefaultDecode<Impl>::drain() 17013133Sgabeblack@google.com{ 17113133Sgabeblack@google.com // Decode is done draining at any time. 17213133Sgabeblack@google.com cpu->signalDrained(); 17312952Sgabeblack@google.com return true; 17412952Sgabeblack@google.com} 17512952Sgabeblack@google.com 17612952Sgabeblack@google.comtemplate <class Impl> 17712952Sgabeblack@google.comvoid 17812952Sgabeblack@google.comDefaultDecode<Impl>::takeOverFrom() 17912952Sgabeblack@google.com{ 18012952Sgabeblack@google.com _status = Inactive; 18112952Sgabeblack@google.com 18212952Sgabeblack@google.com // Be sure to reset state and clear out any old instructions. 18312952Sgabeblack@google.com for (int i = 0; i < numThreads; ++i) { 18412959Sgabeblack@google.com decodeStatus[i] = Idle; 18513133Sgabeblack@google.com 18612959Sgabeblack@google.com stalls[i].rename = false; 18712952Sgabeblack@google.com stalls[i].iew = false; 18812952Sgabeblack@google.com stalls[i].commit = false; 18912952Sgabeblack@google.com while (!insts[i].empty()) 19012952Sgabeblack@google.com insts[i].pop(); 19112952Sgabeblack@google.com while (!skidBuffer[i].empty()) 19212952Sgabeblack@google.com skidBuffer[i].pop(); 19312952Sgabeblack@google.com branchCount[i] = 0; 19412952Sgabeblack@google.com } 19512952Sgabeblack@google.com wroteToTimeBuffer = false; 19612999Sgabeblack@google.com} 19712999Sgabeblack@google.com 19812999Sgabeblack@google.comtemplate<class Impl> 19912999Sgabeblack@google.combool 20012999Sgabeblack@google.comDefaultDecode<Impl>::checkStall(unsigned tid) const 20112999Sgabeblack@google.com{ 20212999Sgabeblack@google.com bool ret_val = false; 20312999Sgabeblack@google.com 20412952Sgabeblack@google.com if (stalls[tid].rename) { 20512952Sgabeblack@google.com DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); 20612952Sgabeblack@google.com ret_val = true; 20712952Sgabeblack@google.com } else if (stalls[tid].iew) { 20812952Sgabeblack@google.com DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); 20912952Sgabeblack@google.com ret_val = true; 21012952Sgabeblack@google.com } else if (stalls[tid].commit) { 21112952Sgabeblack@google.com DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); 21212952Sgabeblack@google.com ret_val = true; 21312952Sgabeblack@google.com } 21412952Sgabeblack@google.com 21512952Sgabeblack@google.com return ret_val; 21612952Sgabeblack@google.com} 21712952Sgabeblack@google.com 21812952Sgabeblack@google.comtemplate<class Impl> 21912952Sgabeblack@google.cominline bool 22013102Sgabeblack@google.comDefaultDecode<Impl>::fetchInstsValid() 22113102Sgabeblack@google.com{ 22213102Sgabeblack@google.com return fromFetch->size > 0; 22313102Sgabeblack@google.com} 22413102Sgabeblack@google.com 22513102Sgabeblack@google.comtemplate<class Impl> 22612952Sgabeblack@google.combool 22712952Sgabeblack@google.comDefaultDecode<Impl>::block(unsigned tid) 22812952Sgabeblack@google.com{ 22912952Sgabeblack@google.com DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); 23012952Sgabeblack@google.com 23112952Sgabeblack@google.com // Add the current inputs to the skid buffer so they can be 23212952Sgabeblack@google.com // reprocessed when this stage unblocks. 23312952Sgabeblack@google.com skidInsert(tid); 23412995Sgabeblack@google.com 23512998Sgabeblack@google.com // If the decode status is blocked or unblocking then decode has not yet 23612995Sgabeblack@google.com // signalled fetch to unblock. In that case, there is no need to tell 23712995Sgabeblack@google.com // fetch to block. 23812998Sgabeblack@google.com if (decodeStatus[tid] != Blocked) { 23912998Sgabeblack@google.com // Set the status to Blocked. 24012998Sgabeblack@google.com decodeStatus[tid] = Blocked; 24112998Sgabeblack@google.com 24212998Sgabeblack@google.com if (decodeStatus[tid] != Unblocking) { 24312998Sgabeblack@google.com toFetch->decodeBlock[tid] = true; 24412952Sgabeblack@google.com wroteToTimeBuffer = true; 24512952Sgabeblack@google.com } 24612952Sgabeblack@google.com 24712952Sgabeblack@google.com return true; 24812952Sgabeblack@google.com } 24913102Sgabeblack@google.com 25013102Sgabeblack@google.com return false; 25113102Sgabeblack@google.com} 25213102Sgabeblack@google.com 25313102Sgabeblack@google.comtemplate<class Impl> 25413102Sgabeblack@google.combool 25512952Sgabeblack@google.comDefaultDecode<Impl>::unblock(unsigned tid) 25612952Sgabeblack@google.com{ 25712952Sgabeblack@google.com // Decode is done unblocking only if the skid buffer is empty. 25812952Sgabeblack@google.com if (skidBuffer[tid].empty()) { 25912952Sgabeblack@google.com DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); 26012952Sgabeblack@google.com toFetch->decodeUnblock[tid] = true; 26112952Sgabeblack@google.com wroteToTimeBuffer = true; 26212952Sgabeblack@google.com 26312995Sgabeblack@google.com decodeStatus[tid] = Running; 26412998Sgabeblack@google.com return true; 26512998Sgabeblack@google.com } 26612998Sgabeblack@google.com 26712998Sgabeblack@google.com DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); 26812998Sgabeblack@google.com 26912998Sgabeblack@google.com return false; 27012952Sgabeblack@google.com} 27112952Sgabeblack@google.com 27212952Sgabeblack@google.comtemplate<class Impl> 27312952Sgabeblack@google.comvoid 27412952Sgabeblack@google.comDefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid) 27512952Sgabeblack@google.com{ 27612952Sgabeblack@google.com DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction " 27713102Sgabeblack@google.com "detected at decode.\n", tid); 27813102Sgabeblack@google.com 27913102Sgabeblack@google.com // Send back mispredict information. 28013102Sgabeblack@google.com toFetch->decodeInfo[tid].branchMispredict = true; 28113102Sgabeblack@google.com toFetch->decodeInfo[tid].predIncorrect = true; 28213102Sgabeblack@google.com toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; 28312952Sgabeblack@google.com toFetch->decodeInfo[tid].squash = true; 28412952Sgabeblack@google.com toFetch->decodeInfo[tid].nextPC = inst->branchTarget(); 28512998Sgabeblack@google.com#if ISA_HAS_DELAY_SLOT 28612998Sgabeblack@google.com toFetch->decodeInfo[tid].branchTaken = inst->readNextNPC() != 28712998Sgabeblack@google.com (inst->readNextPC() + sizeof(TheISA::MachInst)); 28812998Sgabeblack@google.com 28912952Sgabeblack@google.com toFetch->decodeInfo[tid].bdelayDoneSeqNum = bdelayDoneSeqNum[tid]; 29012952Sgabeblack@google.com squashAfterDelaySlot[tid] = false; 29112952Sgabeblack@google.com 29212952Sgabeblack@google.com InstSeqNum squash_seq_num = bdelayDoneSeqNum[tid]; 29312952Sgabeblack@google.com#else 29412952Sgabeblack@google.com toFetch->decodeInfo[tid].branchTaken = 29512995Sgabeblack@google.com inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst)); 29612952Sgabeblack@google.com 29712952Sgabeblack@google.com InstSeqNum squash_seq_num = inst->seqNum; 29812952Sgabeblack@google.com#endif 29912952Sgabeblack@google.com 30012952Sgabeblack@google.com // Might have to tell fetch to unblock. 30112952Sgabeblack@google.com if (decodeStatus[tid] == Blocked || 30212952Sgabeblack@google.com decodeStatus[tid] == Unblocking) { 30312952Sgabeblack@google.com toFetch->decodeUnblock[tid] = 1; 30412952Sgabeblack@google.com } 30512952Sgabeblack@google.com 30612952Sgabeblack@google.com // Set status to squashing. 30712952Sgabeblack@google.com decodeStatus[tid] = Squashing; 30812952Sgabeblack@google.com 30912952Sgabeblack@google.com for (int i=0; i<fromFetch->size; i++) { 31012952Sgabeblack@google.com if (fromFetch->insts[i]->threadNumber == tid && 31112952Sgabeblack@google.com fromFetch->insts[i]->seqNum > squash_seq_num) { 31212952Sgabeblack@google.com fromFetch->insts[i]->setSquashed(); 31312952Sgabeblack@google.com } 31412952Sgabeblack@google.com } 31512952Sgabeblack@google.com 31612952Sgabeblack@google.com // Clear the instruction list and skid buffer in case they have any 31712957Sgabeblack@google.com // insts in them. 31812957Sgabeblack@google.com while (!insts[tid].empty()) { 31912957Sgabeblack@google.com 32012957Sgabeblack@google.com#if ISA_HAS_DELAY_SLOT 32112957Sgabeblack@google.com if (insts[tid].front()->seqNum <= squash_seq_num) { 32212957Sgabeblack@google.com DPRINTF(Decode, "[tid:%i]: Cannot remove incoming decode " 32312957Sgabeblack@google.com "instructions before delay slot [sn:%i]. %i insts" 32412957Sgabeblack@google.com "left in decode.\n", tid, squash_seq_num, 32512957Sgabeblack@google.com insts[tid].size()); 32612957Sgabeblack@google.com break; 32712957Sgabeblack@google.com } 32812957Sgabeblack@google.com#endif 32912957Sgabeblack@google.com insts[tid].pop(); 33012957Sgabeblack@google.com } 33112957Sgabeblack@google.com 33212957Sgabeblack@google.com while (!skidBuffer[tid].empty()) { 33312957Sgabeblack@google.com 33412953Sgabeblack@google.com#if ISA_HAS_DELAY_SLOT 33512952Sgabeblack@google.com if (skidBuffer[tid].front()->seqNum <= squash_seq_num) { 33612953Sgabeblack@google.com DPRINTF(Decode, "[tid:%i]: Cannot remove skidBuffer " 33712953Sgabeblack@google.com "instructions before delay slot [sn:%i]. %i insts" 33812953Sgabeblack@google.com "left in decode.\n", tid, squash_seq_num, 33912953Sgabeblack@google.com insts[tid].size()); 34012953Sgabeblack@google.com break; 34113175Sgabeblack@google.com } 34213175Sgabeblack@google.com#endif 34312995Sgabeblack@google.com skidBuffer[tid].pop(); 34412953Sgabeblack@google.com } 34512995Sgabeblack@google.com 34612953Sgabeblack@google.com // Squash instructions up until this one 34712953Sgabeblack@google.com cpu->removeInstsUntil(squash_seq_num, tid); 34813093Sgabeblack@google.com} 34912953Sgabeblack@google.com 35012952Sgabeblack@google.comtemplate<class Impl> 35112957Sgabeblack@google.comunsigned 35212957Sgabeblack@google.comDefaultDecode<Impl>::squash(unsigned tid) 35312957Sgabeblack@google.com{ 35412957Sgabeblack@google.com DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); 35512957Sgabeblack@google.com 35612957Sgabeblack@google.com if (decodeStatus[tid] == Blocked || 35712957Sgabeblack@google.com decodeStatus[tid] == Unblocking) { 35812957Sgabeblack@google.com#if !FULL_SYSTEM 35912957Sgabeblack@google.com // In syscall emulation, we can have both a block and a squash due 36012957Sgabeblack@google.com // to a syscall in the same cycle. This would cause both signals to 36112957Sgabeblack@google.com // be high. This shouldn't happen in full system. 36212957Sgabeblack@google.com // @todo: Determine if this still happens. 36312957Sgabeblack@google.com if (toFetch->decodeBlock[tid]) { 36412959Sgabeblack@google.com toFetch->decodeBlock[tid] = 0; 36512959Sgabeblack@google.com } else { 36612959Sgabeblack@google.com toFetch->decodeUnblock[tid] = 1; 36712959Sgabeblack@google.com } 36812959Sgabeblack@google.com#else 36912959Sgabeblack@google.com toFetch->decodeUnblock[tid] = 1; 37012959Sgabeblack@google.com#endif 37112959Sgabeblack@google.com } 37212959Sgabeblack@google.com 37312959Sgabeblack@google.com // Set status to squashing. 37412959Sgabeblack@google.com decodeStatus[tid] = Squashing; 37512959Sgabeblack@google.com 37612959Sgabeblack@google.com // Go through incoming instructions from fetch and squash them. 37712959Sgabeblack@google.com unsigned squash_count = 0; 37812996Sgabeblack@google.com 37912996Sgabeblack@google.com for (int i=0; i<fromFetch->size; i++) { 38012959Sgabeblack@google.com if (fromFetch->insts[i]->threadNumber == tid) { 38112959Sgabeblack@google.com fromFetch->insts[i]->setSquashed(); 38212959Sgabeblack@google.com squash_count++; 38312959Sgabeblack@google.com } 38412959Sgabeblack@google.com } 38512959Sgabeblack@google.com 38612997Sgabeblack@google.com // Clear the instruction list and skid buffer in case they have any 38712997Sgabeblack@google.com // insts in them. 38812997Sgabeblack@google.com while (!insts[tid].empty()) { 38912997Sgabeblack@google.com insts[tid].pop(); 39012997Sgabeblack@google.com } 39112997Sgabeblack@google.com 39212997Sgabeblack@google.com while (!skidBuffer[tid].empty()) { 39312997Sgabeblack@google.com skidBuffer[tid].pop(); 39412997Sgabeblack@google.com } 39512997Sgabeblack@google.com 39612997Sgabeblack@google.com return squash_count; 39712997Sgabeblack@google.com} 39812997Sgabeblack@google.com 39913180Sgabeblack@google.comtemplate<class Impl> 40013087Sgabeblack@google.comvoid 40113180Sgabeblack@google.comDefaultDecode<Impl>::skidInsert(unsigned tid) 40213180Sgabeblack@google.com{ 40313180Sgabeblack@google.com DynInstPtr inst = NULL; 40413180Sgabeblack@google.com 40512953Sgabeblack@google.com while (!insts[tid].empty()) { 40613131Sgabeblack@google.com inst = insts[tid].front(); 40713131Sgabeblack@google.com 40813131Sgabeblack@google.com insts[tid].pop(); 40912953Sgabeblack@google.com 41012953Sgabeblack@google.com assert(tid == inst->threadNumber); 41112952Sgabeblack@google.com 41212998Sgabeblack@google.com DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n", 41312998Sgabeblack@google.com inst->seqNum, inst->readPC(), inst->threadNumber); 41412998Sgabeblack@google.com 41512998Sgabeblack@google.com skidBuffer[tid].push(inst); 41612998Sgabeblack@google.com } 41712998Sgabeblack@google.com 41812998Sgabeblack@google.com // @todo: Eventually need to enforce this by not letting a thread 41912998Sgabeblack@google.com // fetch past its skidbuffer 42012998Sgabeblack@google.com assert(skidBuffer[tid].size() <= skidBufferMax); 42112998Sgabeblack@google.com} 42212998Sgabeblack@google.com 42312998Sgabeblack@google.comtemplate<class Impl> 42413006Sgabeblack@google.combool 42513006Sgabeblack@google.comDefaultDecode<Impl>::skidsEmpty() 42612998Sgabeblack@google.com{ 42712998Sgabeblack@google.com std::list<unsigned>::iterator threads = (*activeThreads).begin(); 42812953Sgabeblack@google.com 42912952Sgabeblack@google.com while (threads != (*activeThreads).end()) { 43012952Sgabeblack@google.com if (!skidBuffer[*threads++].empty()) 43112952Sgabeblack@google.com return false; 43212952Sgabeblack@google.com } 43312952Sgabeblack@google.com 43412952Sgabeblack@google.com return true; 43512952Sgabeblack@google.com} 43612952Sgabeblack@google.com 437template<class Impl> 438void 439DefaultDecode<Impl>::updateStatus() 440{ 441 bool any_unblocking = false; 442 443 std::list<unsigned>::iterator threads = (*activeThreads).begin(); 444 445 threads = (*activeThreads).begin(); 446 447 while (threads != (*activeThreads).end()) { 448 unsigned tid = *threads++; 449 450 if (decodeStatus[tid] == Unblocking) { 451 any_unblocking = true; 452 break; 453 } 454 } 455 456 // Decode will have activity if it's unblocking. 457 if (any_unblocking) { 458 if (_status == Inactive) { 459 _status = Active; 460 461 DPRINTF(Activity, "Activating stage.\n"); 462 463 cpu->activateStage(O3CPU::DecodeIdx); 464 } 465 } else { 466 // If it's not unblocking, then decode will not have any internal 467 // activity. Switch it to inactive. 468 if (_status == Active) { 469 _status = Inactive; 470 DPRINTF(Activity, "Deactivating stage.\n"); 471 472 cpu->deactivateStage(O3CPU::DecodeIdx); 473 } 474 } 475} 476 477template <class Impl> 478void 479DefaultDecode<Impl>::sortInsts() 480{ 481 int insts_from_fetch = fromFetch->size; 482#ifdef DEBUG 483 for (int i=0; i < numThreads; i++) 484 assert(insts[i].empty()); 485#endif 486 for (int i = 0; i < insts_from_fetch; ++i) { 487 insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); 488 } 489} 490 491template<class Impl> 492void 493DefaultDecode<Impl>::readStallSignals(unsigned tid) 494{ 495 if (fromRename->renameBlock[tid]) { 496 stalls[tid].rename = true; 497 } 498 499 if (fromRename->renameUnblock[tid]) { 500 assert(stalls[tid].rename); 501 stalls[tid].rename = false; 502 } 503 504 if (fromIEW->iewBlock[tid]) { 505 stalls[tid].iew = true; 506 } 507 508 if (fromIEW->iewUnblock[tid]) { 509 assert(stalls[tid].iew); 510 stalls[tid].iew = false; 511 } 512 513 if (fromCommit->commitBlock[tid]) { 514 stalls[tid].commit = true; 515 } 516 517 if (fromCommit->commitUnblock[tid]) { 518 assert(stalls[tid].commit); 519 stalls[tid].commit = false; 520 } 521} 522 523template <class Impl> 524bool 525DefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid) 526{ 527 // Check if there's a squash signal, squash if there is. 528 // Check stall signals, block if necessary. 529 // If status was blocked 530 // Check if stall conditions have passed 531 // if so then go to unblocking 532 // If status was Squashing 533 // check if squashing is not high. Switch to running this cycle. 534 535 // Update the per thread stall statuses. 536 readStallSignals(tid); 537 538 // Check squash signals from commit. 539 if (fromCommit->commitInfo[tid].squash) { 540 541 DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " 542 "from commit.\n", tid); 543 544 squash(tid); 545 546 return true; 547 } 548 549 // Check ROB squash signals from commit. 550 if (fromCommit->commitInfo[tid].robSquashing) { 551 DPRINTF(Decode, "[tid:%u]: ROB is still squashing.\n", tid); 552 553 // Continue to squash. 554 decodeStatus[tid] = Squashing; 555 556 return true; 557 } 558 559 if (checkStall(tid)) { 560 return block(tid); 561 } 562 563 if (decodeStatus[tid] == Blocked) { 564 DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", 565 tid); 566 567 decodeStatus[tid] = Unblocking; 568 569 unblock(tid); 570 571 return true; 572 } 573 574 if (decodeStatus[tid] == Squashing) { 575 // Switch status to running if decode isn't being told to block or 576 // squash this cycle. 577 DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", 578 tid); 579 580 decodeStatus[tid] = Running; 581 582 return false; 583 } 584 585 // If we've reached this point, we have not gotten any signals that 586 // cause decode to change its status. Decode remains the same as before. 587 return false; 588} 589 590template<class Impl> 591void 592DefaultDecode<Impl>::tick() 593{ 594 wroteToTimeBuffer = false; 595 596 bool status_change = false; 597 598 toRenameIndex = 0; 599 600 std::list<unsigned>::iterator threads = (*activeThreads).begin(); 601 602 sortInsts(); 603 604 //Check stall and squash signals. 605 while (threads != (*activeThreads).end()) { 606 unsigned tid = *threads++; 607 608 DPRINTF(Decode,"Processing [tid:%i]\n",tid); 609 status_change = checkSignalsAndUpdate(tid) || status_change; 610 611 decode(status_change, tid); 612 } 613 614 if (status_change) { 615 updateStatus(); 616 } 617 618 if (wroteToTimeBuffer) { 619 DPRINTF(Activity, "Activity this cycle.\n"); 620 621 cpu->activityThisCycle(); 622 } 623} 624 625template<class Impl> 626void 627DefaultDecode<Impl>::decode(bool &status_change, unsigned tid) 628{ 629 // If status is Running or idle, 630 // call decodeInsts() 631 // If status is Unblocking, 632 // buffer any instructions coming from fetch 633 // continue trying to empty skid buffer 634 // check if stall conditions have passed 635 636 if (decodeStatus[tid] == Blocked) { 637 ++decodeBlockedCycles; 638 } else if (decodeStatus[tid] == Squashing) { 639 ++decodeSquashCycles; 640 } 641 642 // Decode should try to decode as many instructions as its bandwidth 643 // will allow, as long as it is not currently blocked. 644 if (decodeStatus[tid] == Running || 645 decodeStatus[tid] == Idle) { 646 DPRINTF(Decode, "[tid:%u]: Not blocked, so attempting to run " 647 "stage.\n",tid); 648 649 decodeInsts(tid); 650 } else if (decodeStatus[tid] == Unblocking) { 651 // Make sure that the skid buffer has something in it if the 652 // status is unblocking. 653 assert(!skidsEmpty()); 654 655 // If the status was unblocking, then instructions from the skid 656 // buffer were used. Remove those instructions and handle 657 // the rest of unblocking. 658 decodeInsts(tid); 659 660 if (fetchInstsValid()) { 661 // Add the current inputs to the skid buffer so they can be 662 // reprocessed when this stage unblocks. 663 skidInsert(tid); 664 } 665 666 status_change = unblock(tid) || status_change; 667 } 668} 669 670template <class Impl> 671void 672DefaultDecode<Impl>::decodeInsts(unsigned tid) 673{ 674 // Instructions can come either from the skid buffer or the list of 675 // instructions coming from fetch, depending on decode's status. 676 int insts_available = decodeStatus[tid] == Unblocking ? 677 skidBuffer[tid].size() : insts[tid].size(); 678 679 if (insts_available == 0) { 680 DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" 681 " early.\n",tid); 682 // Should I change the status to idle? 683 ++decodeIdleCycles; 684 return; 685 } else if (decodeStatus[tid] == Unblocking) { 686 DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " 687 "buffer.\n",tid); 688 ++decodeUnblockCycles; 689 } else if (decodeStatus[tid] == Running) { 690 ++decodeRunCycles; 691 } 692 693 DynInstPtr inst; 694 695 std::queue<DynInstPtr> 696 &insts_to_decode = decodeStatus[tid] == Unblocking ? 697 skidBuffer[tid] : insts[tid]; 698 699 DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); 700 701 while (insts_available > 0 && toRenameIndex < decodeWidth) { 702 assert(!insts_to_decode.empty()); 703 704 inst = insts_to_decode.front(); 705 706 insts_to_decode.pop(); 707 708 DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " 709 "PC %#x\n", 710 tid, inst->seqNum, inst->readPC()); 711 712 if (inst->isSquashed()) { 713 DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is " 714 "squashed, skipping.\n", 715 tid, inst->seqNum, inst->readPC()); 716 717 ++decodeSquashedInsts; 718 719 --insts_available; 720 721 continue; 722 } 723 724 // Also check if instructions have no source registers. Mark 725 // them as ready to issue at any time. Not sure if this check 726 // should exist here or at a later stage; however it doesn't matter 727 // too much for function correctness. 728 if (inst->numSrcRegs() == 0) { 729 inst->setCanIssue(); 730 } 731 732 // This current instruction is valid, so add it into the decode 733 // queue. The next instruction may not be valid, so check to 734 // see if branches were predicted correctly. 735 toRename->insts[toRenameIndex] = inst; 736 737 ++(toRename->size); 738 ++toRenameIndex; 739 ++decodeDecodedInsts; 740 --insts_available; 741 742 // Ensure that if it was predicted as a branch, it really is a 743 // branch. 744 if (inst->predTaken() && !inst->isControl()) { 745 DPRINTF(Decode, "PredPC : %#x != NextPC: %#x\n",inst->predPC, 746 inst->nextPC + 4); 747 748 panic("Instruction predicted as a branch!"); 749 750 ++decodeControlMispred; 751 752 // Might want to set some sort of boolean and just do 753 // a check at the end 754 squash(inst, inst->threadNumber); 755 756 break; 757 } 758 759 // Go ahead and compute any PC-relative branches. 760 if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 761 ++decodeBranchResolved; 762 763 if (inst->branchTarget() != inst->readPredTarg()) { 764 ++decodeBranchMispred; 765 766 // Might want to set some sort of boolean and just do 767 // a check at the end 768#if !ISA_HAS_DELAY_SLOT 769 squash(inst, inst->threadNumber); 770 inst->setPredTarg(inst->branchTarget()); 771 break; 772#else 773 // If mispredicted as taken, then ignore delay slot 774 // instruction... else keep delay slot and squash 775 // after it is sent to rename 776 if (inst->predTaken() && inst->isCondDelaySlot()) { 777 DPRINTF(Decode, "[tid:%i]: Conditional delay slot inst." 778 "[sn:%i] PC %#x mispredicted as taken.\n", tid, 779 inst->seqNum, inst->PC); 780 bdelayDoneSeqNum[tid] = inst->seqNum; 781 squash(inst, inst->threadNumber); 782 inst->setPredTarg(inst->branchTarget()); 783 break; 784 } else { 785 DPRINTF(Decode, "[tid:%i]: Misprediction detected at " 786 "[sn:%i] PC %#x, will squash after delay slot " 787 "inst. is sent to Rename\n", 788 tid, inst->seqNum, inst->PC); 789 bdelayDoneSeqNum[tid] = inst->seqNum + 1; 790 squashAfterDelaySlot[tid] = true; 791 squashInst[tid] = inst; 792 continue; 793 } 794#endif 795 } 796 } 797 798 if (squashAfterDelaySlot[tid]) { 799 assert(!inst->isSquashed()); 800 squash(squashInst[tid], squashInst[tid]->threadNumber); 801 squashInst[tid]->setPredTarg(squashInst[tid]->branchTarget()); 802 assert(!inst->isSquashed()); 803 break; 804 } 805 } 806 807 // If we didn't process all instructions, then we will need to block 808 // and put all those instructions into the skid buffer. 809 if (!insts_to_decode.empty()) { 810 block(tid); 811 } 812 813 // Record that decode has written to the time buffer for activity 814 // tracking. 815 if (toRenameIndex) { 816 wroteToTimeBuffer = true; 817 } 818} 819