decode_impl.hh revision 1061
111731Sjason@lowepower.com#ifndef __SIMPLE_DECODE_CC__ 211731Sjason@lowepower.com#define __SIMPLE_DECODE_CC__ 311731Sjason@lowepower.com 411731Sjason@lowepower.com#include "cpu/beta_cpu/decode.hh" 511731Sjason@lowepower.com 611731Sjason@lowepower.comtemplate<class Impl> 711731Sjason@lowepower.comSimpleDecode<Impl>::SimpleDecode(Params ¶ms) 811731Sjason@lowepower.com : renameToDecodeDelay(params.renameToDecodeDelay), 911731Sjason@lowepower.com iewToDecodeDelay(params.iewToDecodeDelay), 1011731Sjason@lowepower.com commitToDecodeDelay(params.commitToDecodeDelay), 1111731Sjason@lowepower.com fetchToDecodeDelay(params.fetchToDecodeDelay), 1211731Sjason@lowepower.com decodeWidth(params.decodeWidth), 1311731Sjason@lowepower.com numInst(0) 1411731Sjason@lowepower.com{ 1511731Sjason@lowepower.com DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth); 1611731Sjason@lowepower.com _status = Idle; 1711731Sjason@lowepower.com} 1811731Sjason@lowepower.com 1911731Sjason@lowepower.comtemplate<class Impl> 2011731Sjason@lowepower.comvoid 2111731Sjason@lowepower.comSimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr) 2211731Sjason@lowepower.com{ 2311731Sjason@lowepower.com DPRINTF(Decode, "Decode: Setting CPU pointer.\n"); 2411731Sjason@lowepower.com cpu = cpu_ptr; 2511731Sjason@lowepower.com} 2611731Sjason@lowepower.com 2711731Sjason@lowepower.comtemplate<class Impl> 2811731Sjason@lowepower.comvoid 2911731Sjason@lowepower.comSimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 3011731Sjason@lowepower.com{ 3111731Sjason@lowepower.com DPRINTF(Decode, "Decode: Setting time buffer pointer.\n"); 3211731Sjason@lowepower.com timeBuffer = tb_ptr; 3311731Sjason@lowepower.com 3411731Sjason@lowepower.com // Setup wire to write information back to fetch. 3511731Sjason@lowepower.com toFetch = timeBuffer->getWire(0); 3611731Sjason@lowepower.com 3711731Sjason@lowepower.com // Create wires to get information from proper places in time buffer. 3811731Sjason@lowepower.com fromRename = timeBuffer->getWire(-renameToDecodeDelay); 3911731Sjason@lowepower.com fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 4011731Sjason@lowepower.com fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 4111731Sjason@lowepower.com} 4211731Sjason@lowepower.com 4311731Sjason@lowepower.comtemplate<class Impl> 4411731Sjason@lowepower.comvoid 4511731Sjason@lowepower.comSimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 4611731Sjason@lowepower.com{ 4711731Sjason@lowepower.com DPRINTF(Decode, "Decode: Setting decode queue pointer.\n"); 4811731Sjason@lowepower.com decodeQueue = dq_ptr; 4911731Sjason@lowepower.com 5011731Sjason@lowepower.com // Setup wire to write information to proper place in decode queue. 5111731Sjason@lowepower.com toRename = decodeQueue->getWire(0); 5211731Sjason@lowepower.com} 5311731Sjason@lowepower.com 5411731Sjason@lowepower.comtemplate<class Impl> 5511731Sjason@lowepower.comvoid 5611731Sjason@lowepower.comSimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 5711731Sjason@lowepower.com{ 5811731Sjason@lowepower.com DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n"); 5911731Sjason@lowepower.com fetchQueue = fq_ptr; 6011731Sjason@lowepower.com 6111731Sjason@lowepower.com // Setup wire to read information from fetch queue. 6211731Sjason@lowepower.com fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 6311731Sjason@lowepower.com} 6411731Sjason@lowepower.com 6511731Sjason@lowepower.comtemplate<class Impl> 6611731Sjason@lowepower.comvoid 6711731Sjason@lowepower.comSimpleDecode<Impl>::block() 6811731Sjason@lowepower.com{ 6911731Sjason@lowepower.com DPRINTF(Decode, "Decode: Blocking.\n"); 7011731Sjason@lowepower.com 7111731Sjason@lowepower.com // Set the status to Blocked. 7211731Sjason@lowepower.com _status = Blocked; 7311731Sjason@lowepower.com 7411731Sjason@lowepower.com // Add the current inputs to the skid buffer so they can be 7511731Sjason@lowepower.com // reprocessed when this stage unblocks. 7611731Sjason@lowepower.com skidBuffer.push(*fromFetch); 7711731Sjason@lowepower.com 7811731Sjason@lowepower.com // Note that this stage only signals previous stages to stall when 7911731Sjason@lowepower.com // it is the cause of the stall originates at this stage. Otherwise 8011731Sjason@lowepower.com // the previous stages are expected to check all possible stall signals. 8111731Sjason@lowepower.com} 8211731Sjason@lowepower.com 8311731Sjason@lowepower.comtemplate<class Impl> 8411731Sjason@lowepower.cominline void 8511731Sjason@lowepower.comSimpleDecode<Impl>::unblock() 8611731Sjason@lowepower.com{ 8711731Sjason@lowepower.com DPRINTF(Decode, "Decode: Unblocking, going to remove " 8811731Sjason@lowepower.com "instructions from skid buffer.\n"); 8911731Sjason@lowepower.com // Remove the now processed instructions from the skid buffer. 9011731Sjason@lowepower.com skidBuffer.pop(); 9111731Sjason@lowepower.com 9211731Sjason@lowepower.com // If there's still information in the skid buffer, then 9311731Sjason@lowepower.com // continue to tell previous stages to stall. They will be 9411731Sjason@lowepower.com // able to restart once the skid buffer is empty. 9511731Sjason@lowepower.com if (!skidBuffer.empty()) { 9611731Sjason@lowepower.com toFetch->decodeInfo.stall = true; 9711731Sjason@lowepower.com } else { 9811731Sjason@lowepower.com DPRINTF(Decode, "Decode: Finished unblocking.\n"); 9911731Sjason@lowepower.com _status = Running; 10011731Sjason@lowepower.com } 10111731Sjason@lowepower.com} 10211731Sjason@lowepower.com 10311731Sjason@lowepower.com// This squash is specifically for when Decode detects a PC-relative branch 10411731Sjason@lowepower.com// was predicted incorrectly. 10511731Sjason@lowepower.comtemplate<class Impl> 10611731Sjason@lowepower.comvoid 10711731Sjason@lowepower.comSimpleDecode<Impl>::squash(DynInstPtr &inst) 10811731Sjason@lowepower.com{ 10911731Sjason@lowepower.com DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction " 11011731Sjason@lowepower.com "detected at decode.\n"); 11111731Sjason@lowepower.com Addr new_PC = inst->nextPC; 11211731Sjason@lowepower.com 11311731Sjason@lowepower.com toFetch->decodeInfo.predIncorrect = true; 11411731Sjason@lowepower.com toFetch->decodeInfo.squash = true; 11511731Sjason@lowepower.com toFetch->decodeInfo.nextPC = new_PC; 11611731Sjason@lowepower.com 11711731Sjason@lowepower.com // Set status to squashing. 11811731Sjason@lowepower.com _status = Squashing; 11911731Sjason@lowepower.com 12011731Sjason@lowepower.com // Maybe advance the time buffer? Not sure what to do in the normal 12111731Sjason@lowepower.com // case. 12211731Sjason@lowepower.com 12311731Sjason@lowepower.com // Clear the skid buffer in case it has any data in it. 12411731Sjason@lowepower.com while (!skidBuffer.empty()) 12511731Sjason@lowepower.com { 12611731Sjason@lowepower.com skidBuffer.pop(); 12711731Sjason@lowepower.com } 12811731Sjason@lowepower.com} 12911731Sjason@lowepower.com 13011731Sjason@lowepower.comtemplate<class Impl> 13111731Sjason@lowepower.comvoid 13211731Sjason@lowepower.comSimpleDecode<Impl>::squash() 13311731Sjason@lowepower.com{ 13411731Sjason@lowepower.com DPRINTF(Decode, "Decode: Squashing.\n"); 13511731Sjason@lowepower.com // Set status to squashing. 13611731Sjason@lowepower.com _status = Squashing; 13711731Sjason@lowepower.com 13811731Sjason@lowepower.com // Maybe advance the time buffer? Not sure what to do in the normal 13911731Sjason@lowepower.com // case. 14011731Sjason@lowepower.com 14111731Sjason@lowepower.com // Clear the skid buffer in case it has any data in it. 14211731Sjason@lowepower.com while (!skidBuffer.empty()) 14311731Sjason@lowepower.com { 14411731Sjason@lowepower.com skidBuffer.pop(); 14511731Sjason@lowepower.com } 14611731Sjason@lowepower.com} 14711731Sjason@lowepower.com 14811731Sjason@lowepower.comtemplate<class Impl> 14911731Sjason@lowepower.comvoid 15011731Sjason@lowepower.comSimpleDecode<Impl>::tick() 15111731Sjason@lowepower.com{ 15211731Sjason@lowepower.com // Decode should try to execute as many instructions as its bandwidth 15311731Sjason@lowepower.com // will allow, as long as it is not currently blocked. 15411731Sjason@lowepower.com if (_status != Blocked && _status != Squashing) { 15511731Sjason@lowepower.com DPRINTF(Decode, "Decode: Not blocked, so attempting to run " 15611731Sjason@lowepower.com "stage.\n"); 15711731Sjason@lowepower.com // Make sure that the skid buffer has something in it if the 15811731Sjason@lowepower.com // status is unblocking. 15911731Sjason@lowepower.com assert(_status == Unblocking ? !skidBuffer.empty() : 1); 16011731Sjason@lowepower.com 16111731Sjason@lowepower.com decode(); 16211731Sjason@lowepower.com 16311731Sjason@lowepower.com // If the status was unblocking, then instructions from the skid 16411731Sjason@lowepower.com // buffer were used. Remove those instructions and handle 16511731Sjason@lowepower.com // the rest of unblocking. 16611731Sjason@lowepower.com if (_status == Unblocking) { 16711731Sjason@lowepower.com if (fromFetch->size > 0) { 16811731Sjason@lowepower.com // Add the current inputs to the skid buffer so they can be 16911731Sjason@lowepower.com // reprocessed when this stage unblocks. 17012137Sar4jc@virginia.edu skidBuffer.push(*fromFetch); 17112137Sar4jc@virginia.edu } 17211731Sjason@lowepower.com 17311731Sjason@lowepower.com unblock(); 17411731Sjason@lowepower.com } 17511731Sjason@lowepower.com } else if (_status == Blocked) { 17611731Sjason@lowepower.com if (fromFetch->size > 0) { 17711731Sjason@lowepower.com block(); 17811731Sjason@lowepower.com } 17911731Sjason@lowepower.com 18011731Sjason@lowepower.com if (!fromRename->renameInfo.stall && 18111731Sjason@lowepower.com !fromIEW->iewInfo.stall && 18211731Sjason@lowepower.com !fromCommit->commitInfo.stall) { 18311731Sjason@lowepower.com DPRINTF(Decode, "Decode: Stall signals cleared, going to " 18411731Sjason@lowepower.com "unblock.\n"); 18511731Sjason@lowepower.com _status = Unblocking; 18611731Sjason@lowepower.com 18711731Sjason@lowepower.com // Continue to tell previous stage to block until this 18811731Sjason@lowepower.com // stage is done unblocking. 18911731Sjason@lowepower.com toFetch->decodeInfo.stall = true; 19011731Sjason@lowepower.com } else { 19111731Sjason@lowepower.com DPRINTF(Decode, "Decode: Still blocked.\n"); 19211731Sjason@lowepower.com toFetch->decodeInfo.stall = true; 19311731Sjason@lowepower.com } 19411731Sjason@lowepower.com 19511731Sjason@lowepower.com if (fromCommit->commitInfo.squash || 19611731Sjason@lowepower.com fromCommit->commitInfo.robSquashing) { 19711731Sjason@lowepower.com squash(); 19811731Sjason@lowepower.com } 19911731Sjason@lowepower.com } else if (_status == Squashing) { 20011731Sjason@lowepower.com if (!fromCommit->commitInfo.squash && 20111731Sjason@lowepower.com !fromCommit->commitInfo.robSquashing) { 20211731Sjason@lowepower.com _status = Running; 20311731Sjason@lowepower.com } else if (fromCommit->commitInfo.squash) { 20411731Sjason@lowepower.com squash(); 20511731Sjason@lowepower.com } 20611731Sjason@lowepower.com } 20711731Sjason@lowepower.com} 20811731Sjason@lowepower.com 20911731Sjason@lowepower.comtemplate<class Impl> 21011731Sjason@lowepower.comvoid 21111731Sjason@lowepower.comSimpleDecode<Impl>::decode() 21211731Sjason@lowepower.com{ 21311731Sjason@lowepower.com // Check time buffer if being told to squash. 21411731Sjason@lowepower.com if (fromCommit->commitInfo.squash) { 21511731Sjason@lowepower.com squash(); 21611731Sjason@lowepower.com return; 21711731Sjason@lowepower.com } 21811731Sjason@lowepower.com 21911731Sjason@lowepower.com // Check time buffer if being told to stall. 22011731Sjason@lowepower.com if (fromRename->renameInfo.stall || 22111731Sjason@lowepower.com fromIEW->iewInfo.stall || 22211731Sjason@lowepower.com fromCommit->commitInfo.stall) 22311731Sjason@lowepower.com { 22411731Sjason@lowepower.com block(); 22511731Sjason@lowepower.com return; 22611731Sjason@lowepower.com } 22711731Sjason@lowepower.com 22811731Sjason@lowepower.com // Check fetch queue to see if instructions are available. 22911731Sjason@lowepower.com // If no available instructions, do nothing, unless this stage is 23011731Sjason@lowepower.com // currently unblocking. 23111731Sjason@lowepower.com if (!fromFetch->insts[0] && _status != Unblocking) { 23211731Sjason@lowepower.com DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); 23311731Sjason@lowepower.com // Should I change the status to idle? 23411731Sjason@lowepower.com return; 23511731Sjason@lowepower.com } 23611731Sjason@lowepower.com 23711731Sjason@lowepower.com DynInstPtr inst; 23811731Sjason@lowepower.com 23911731Sjason@lowepower.com // Instead have a class member variable that records which instruction 24011731Sjason@lowepower.com // was the last one that was ended on. At the tick() stage, it can 24111731Sjason@lowepower.com // check if that's equal to 0. If not, then don't pop stuff off. 24211731Sjason@lowepower.com unsigned to_rename_index = 0; 24311731Sjason@lowepower.com 24412137Sar4jc@virginia.edu int insts_available = _status == Unblocking ? 24512137Sar4jc@virginia.edu skidBuffer.front().size : 24612137Sar4jc@virginia.edu fromFetch->size; 24711731Sjason@lowepower.com 24811731Sjason@lowepower.com // Debug block... 24911731Sjason@lowepower.com#if 0 25011731Sjason@lowepower.com if (insts_available) { 25111731Sjason@lowepower.com DPRINTF(Decode, "Decode: Instructions available.\n"); 25211731Sjason@lowepower.com } else { 25311731Sjason@lowepower.com if (_status == Unblocking && skidBuffer.empty()) { 25411731Sjason@lowepower.com DPRINTF(Decode, "Decode: No instructions available, skid buffer " 25511731Sjason@lowepower.com "empty.\n"); 25611731Sjason@lowepower.com } else if (_status != Unblocking && 25711731Sjason@lowepower.com !fromFetch->insts[0]) { 25811731Sjason@lowepower.com DPRINTF(Decode, "Decode: No instructions available, fetch queue " 25911731Sjason@lowepower.com "empty.\n"); 26011731Sjason@lowepower.com } else { 26111731Sjason@lowepower.com panic("Decode: No instructions available, unexpected condition!" 26211731Sjason@lowepower.com "\n"); 26311731Sjason@lowepower.com } 26411731Sjason@lowepower.com } 26511731Sjason@lowepower.com#endif 26611731Sjason@lowepower.com 26711731Sjason@lowepower.com // Check to make sure that instructions coming from fetch are valid. 26811731Sjason@lowepower.com // Normally at this stage the branch target of PC-relative branches 26911731Sjason@lowepower.com // should be computed here. However in this simple model all 27011731Sjason@lowepower.com // computation will take place at execute. Hence doneTargCalc() 27111731Sjason@lowepower.com // will always be false. 27211731Sjason@lowepower.com while (insts_available > 0) 27311731Sjason@lowepower.com { 27411731Sjason@lowepower.com DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); 27511731Sjason@lowepower.com // Might create some sort of accessor to get an instruction 27611731Sjason@lowepower.com // on a per thread basis. Or might be faster to just get 27711731Sjason@lowepower.com // a pointer to an array or list of instructions and use that 27811731Sjason@lowepower.com // within this code. 27911731Sjason@lowepower.com inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : 28011731Sjason@lowepower.com fromFetch->insts[numInst]; 28111731Sjason@lowepower.com 28211731Sjason@lowepower.com DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n", 28311731Sjason@lowepower.com inst->seqNum, inst->readPC()); 28411731Sjason@lowepower.com 28511731Sjason@lowepower.com if (inst->isSquashed()) { 28611731Sjason@lowepower.com DPRINTF(Decode, "Decode: Instruction %i with PC %#x is " 28711731Sjason@lowepower.com "squashed, skipping.\n", 28811731Sjason@lowepower.com inst->seqNum, inst->readPC()); 28911731Sjason@lowepower.com 29011731Sjason@lowepower.com ++numInst; 29111731Sjason@lowepower.com --insts_available; 29211731Sjason@lowepower.com 29311731Sjason@lowepower.com continue; 29411731Sjason@lowepower.com } 29511731Sjason@lowepower.com 29611731Sjason@lowepower.com // This current instruction is valid, so add it into the decode 29711731Sjason@lowepower.com // queue. The next instruction may not be valid, so check to 29811731Sjason@lowepower.com // see if branches were predicted correctly. 29911731Sjason@lowepower.com toRename->insts[to_rename_index] = inst; 30011731Sjason@lowepower.com 30111731Sjason@lowepower.com ++(toRename->size); 30211731Sjason@lowepower.com 30311731Sjason@lowepower.com // Ensure that if it was predicted as a branch, it really is a 30411731Sjason@lowepower.com // branch. 30511731Sjason@lowepower.com if (inst->predTaken() && !inst->isControl()) { 30611731Sjason@lowepower.com panic("Instruction predicted as a branch!"); 30711731Sjason@lowepower.com 30811731Sjason@lowepower.com // Might want to set some sort of boolean and just do 30911731Sjason@lowepower.com // a check at the end 31011731Sjason@lowepower.com squash(inst); 31111731Sjason@lowepower.com break; 31211731Sjason@lowepower.com } 31311731Sjason@lowepower.com 31411731Sjason@lowepower.com // Ensure that the predicted branch target is the actual branch 31511731Sjason@lowepower.com // target if possible (branches that are PC relative). 31611731Sjason@lowepower.com if (inst->isControl() && inst->doneTargCalc()) { 31711731Sjason@lowepower.com if (inst->mispredicted()) { 31811731Sjason@lowepower.com // Might want to set some sort of boolean and just do 31911731Sjason@lowepower.com // a check at the end 32011731Sjason@lowepower.com squash(inst); 32111731Sjason@lowepower.com break; 32211731Sjason@lowepower.com } 32311731Sjason@lowepower.com } 32411731Sjason@lowepower.com 32511731Sjason@lowepower.com // Also check if instructions have no source registers. Mark 32611731Sjason@lowepower.com // them as ready to issue at any time. Not sure if this check 32711731Sjason@lowepower.com // should exist here or at a later stage; however it doesn't matter 32811731Sjason@lowepower.com // too much for function correctness. 32911731Sjason@lowepower.com // Isn't this handled by the inst queue? 33011731Sjason@lowepower.com if (inst->numSrcRegs() == 0) { 33111731Sjason@lowepower.com inst->setCanIssue(); 33211731Sjason@lowepower.com } 33311731Sjason@lowepower.com 33411731Sjason@lowepower.com // Increment which instruction we're looking at. 33511731Sjason@lowepower.com ++numInst; 33611731Sjason@lowepower.com ++to_rename_index; 33711731Sjason@lowepower.com 33811731Sjason@lowepower.com --insts_available; 33911731Sjason@lowepower.com } 34011731Sjason@lowepower.com 34111731Sjason@lowepower.com numInst = 0; 34211731Sjason@lowepower.com} 34311731Sjason@lowepower.com 34411731Sjason@lowepower.com#endif // __SIMPLE_DECODE_CC__ 34511731Sjason@lowepower.com