| /* | |
| * Copyright (c) 2010-2012, 2014 ARM Limited | |
| * Copyright (c) 2013 Advanced Micro Devices, Inc. | |
| * All rights reserved. | |
| * | |
| * The license below extends only to copyright in the software and shall | |
| * not be construed as granting a license to any other intellectual | |
| * property including but not limited to intellectual property relating | |
| * to a hardware implementation of the functionality of the software | |
| * licensed hereunder. You may use the software subject to the license | |
| * terms below provided that you ensure that this notice is replicated | |
| * unmodified and in its entirety in all distributions of the software, | |
| * modified or unmodified, in source code or in binary form. | |
| * | |
| * Copyright (c) 2004-2006 The Regents of The University of Michigan | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Authors: Kevin Lim | |
| * Korey Sewell | |
| */ | |
| #ifndef __CPU_O3_RENAME_IMPL_HH__ | |
| #define __CPU_O3_RENAME_IMPL_HH__ | |
| #include <list> | |
| #include "arch/isa_traits.hh" | |
| #include "arch/registers.hh" | |
| #include "config/the_isa.hh" | |
| #include "cpu/o3/rename.hh" | |
| #include "cpu/reg_class.hh" | |
| #include "debug/Activity.hh" | |
| #include "debug/Rename.hh" | |
| #include "debug/O3PipeView.hh" | |
| #include "params/DerivO3CPU.hh" | |
| using namespace std; | |
| template <class Impl> | |
| DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params) | |
| : cpu(_cpu), | |
| iewToRenameDelay(params->iewToRenameDelay), | |
| decodeToRenameDelay(params->decodeToRenameDelay), | |
| commitToRenameDelay(params->commitToRenameDelay), | |
| renameWidth(params->renameWidth), | |
| commitWidth(params->commitWidth), | |
| numThreads(params->numThreads), | |
| maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs | |
| + params->numPhysCCRegs) | |
| { | |
| if (renameWidth > Impl::MaxWidth) | |
| fatal("renameWidth (%d) is larger than compiled limit (%d),\n" | |
| "\tincrease MaxWidth in src/cpu/o3/impl.hh\n", | |
| renameWidth, static_cast<int>(Impl::MaxWidth)); | |
| // @todo: Make into a parameter. | |
| skidBufferMax = (decodeToRenameDelay + 1) * params->decodeWidth; | |
| } | |
| template <class Impl> | |
| std::string | |
| DefaultRename<Impl>::name() const | |
| { | |
| return cpu->name() + ".rename"; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::regStats() | |
| { | |
| renameSquashCycles | |
| .name(name() + ".SquashCycles") | |
| .desc("Number of cycles rename is squashing") | |
| .prereq(renameSquashCycles); | |
| renameIdleCycles | |
| .name(name() + ".IdleCycles") | |
| .desc("Number of cycles rename is idle") | |
| .prereq(renameIdleCycles); | |
| renameBlockCycles | |
| .name(name() + ".BlockCycles") | |
| .desc("Number of cycles rename is blocking") | |
| .prereq(renameBlockCycles); | |
| renameSerializeStallCycles | |
| .name(name() + ".serializeStallCycles") | |
| .desc("count of cycles rename stalled for serializing inst") | |
| .flags(Stats::total); | |
| renameRunCycles | |
| .name(name() + ".RunCycles") | |
| .desc("Number of cycles rename is running") | |
| .prereq(renameIdleCycles); | |
| renameUnblockCycles | |
| .name(name() + ".UnblockCycles") | |
| .desc("Number of cycles rename is unblocking") | |
| .prereq(renameUnblockCycles); | |
| renameRenamedInsts | |
| .name(name() + ".RenamedInsts") | |
| .desc("Number of instructions processed by rename") | |
| .prereq(renameRenamedInsts); | |
| renameSquashedInsts | |
| .name(name() + ".SquashedInsts") | |
| .desc("Number of squashed instructions processed by rename") | |
| .prereq(renameSquashedInsts); | |
| renameROBFullEvents | |
| .name(name() + ".ROBFullEvents") | |
| .desc("Number of times rename has blocked due to ROB full") | |
| .prereq(renameROBFullEvents); | |
| renameIQFullEvents | |
| .name(name() + ".IQFullEvents") | |
| .desc("Number of times rename has blocked due to IQ full") | |
| .prereq(renameIQFullEvents); | |
| renameLQFullEvents | |
| .name(name() + ".LQFullEvents") | |
| .desc("Number of times rename has blocked due to LQ full") | |
| .prereq(renameLQFullEvents); | |
| renameSQFullEvents | |
| .name(name() + ".SQFullEvents") | |
| .desc("Number of times rename has blocked due to SQ full") | |
| .prereq(renameSQFullEvents); | |
| renameFullRegistersEvents | |
| .name(name() + ".FullRegisterEvents") | |
| .desc("Number of times there has been no free registers") | |
| .prereq(renameFullRegistersEvents); | |
| renameRenamedOperands | |
| .name(name() + ".RenamedOperands") | |
| .desc("Number of destination operands rename has renamed") | |
| .prereq(renameRenamedOperands); | |
| renameRenameLookups | |
| .name(name() + ".RenameLookups") | |
| .desc("Number of register rename lookups that rename has made") | |
| .prereq(renameRenameLookups); | |
| renameCommittedMaps | |
| .name(name() + ".CommittedMaps") | |
| .desc("Number of HB maps that are committed") | |
| .prereq(renameCommittedMaps); | |
| renameUndoneMaps | |
| .name(name() + ".UndoneMaps") | |
| .desc("Number of HB maps that are undone due to squashing") | |
| .prereq(renameUndoneMaps); | |
| renamedSerializing | |
| .name(name() + ".serializingInsts") | |
| .desc("count of serializing insts renamed") | |
| .flags(Stats::total) | |
| ; | |
| renamedTempSerializing | |
| .name(name() + ".tempSerializingInsts") | |
| .desc("count of temporary serializing insts renamed") | |
| .flags(Stats::total) | |
| ; | |
| renameSkidInsts | |
| .name(name() + ".skidInsts") | |
| .desc("count of insts added to the skid buffer") | |
| .flags(Stats::total) | |
| ; | |
| intRenameLookups | |
| .name(name() + ".int_rename_lookups") | |
| .desc("Number of integer rename lookups") | |
| .prereq(intRenameLookups); | |
| fpRenameLookups | |
| .name(name() + ".fp_rename_lookups") | |
| .desc("Number of floating rename lookups") | |
| .prereq(fpRenameLookups); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) | |
| { | |
| timeBuffer = tb_ptr; | |
| // Setup wire to read information from time buffer, from IEW stage. | |
| fromIEW = timeBuffer->getWire(-iewToRenameDelay); | |
| // Setup wire to read infromation from time buffer, from commit stage. | |
| fromCommit = timeBuffer->getWire(-commitToRenameDelay); | |
| // Setup wire to write information to previous stages. | |
| toDecode = timeBuffer->getWire(0); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) | |
| { | |
| renameQueue = rq_ptr; | |
| // Setup wire to write information to future stages. | |
| toIEW = renameQueue->getWire(0); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) | |
| { | |
| decodeQueue = dq_ptr; | |
| // Setup wire to get information from decode. | |
| fromDecode = decodeQueue->getWire(-decodeToRenameDelay); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::startupStage() | |
| { | |
| resetStage(); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::resetStage() | |
| { | |
| _status = Inactive; | |
| resumeSerialize = false; | |
| resumeUnblocking = false; | |
| // Grab the number of free entries directly from the stages. | |
| for (ThreadID tid = 0; tid < numThreads; tid++) { | |
| renameStatus[tid] = Idle; | |
| freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid); | |
| freeEntries[tid].lqEntries = iew_ptr->ldstQueue.numFreeLoadEntries(tid); | |
| freeEntries[tid].sqEntries = iew_ptr->ldstQueue.numFreeStoreEntries(tid); | |
| freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid); | |
| emptyROB[tid] = true; | |
| stalls[tid].iew = false; | |
| serializeInst[tid] = NULL; | |
| instsInProgress[tid] = 0; | |
| loadsInProgress[tid] = 0; | |
| storesInProgress[tid] = 0; | |
| serializeOnNextInst[tid] = false; | |
| } | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::setActiveThreads(list<ThreadID> *at_ptr) | |
| { | |
| activeThreads = at_ptr; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::setRenameMap(RenameMap rm_ptr[]) | |
| { | |
| for (ThreadID tid = 0; tid < numThreads; tid++) | |
| renameMap[tid] = &rm_ptr[tid]; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::setFreeList(FreeList *fl_ptr) | |
| { | |
| freeList = fl_ptr; | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard) | |
| { | |
| scoreboard = _scoreboard; | |
| } | |
| template <class Impl> | |
| bool | |
| DefaultRename<Impl>::isDrained() const | |
| { | |
| for (ThreadID tid = 0; tid < numThreads; tid++) { | |
| if (instsInProgress[tid] != 0 || | |
| !historyBuffer[tid].empty() || | |
| !skidBuffer[tid].empty() || | |
| !insts[tid].empty()) | |
| return false; | |
| } | |
| return true; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::takeOverFrom() | |
| { | |
| resetStage(); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::drainSanityCheck() const | |
| { | |
| for (ThreadID tid = 0; tid < numThreads; tid++) { | |
| assert(historyBuffer[tid].empty()); | |
| assert(insts[tid].empty()); | |
| assert(skidBuffer[tid].empty()); | |
| assert(instsInProgress[tid] == 0); | |
| } | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::squash(const InstSeqNum &squash_seq_num, ThreadID tid) | |
| { | |
| DPRINTF(Rename, "[tid:%u]: Squashing instructions.\n",tid); | |
| // Clear the stall signal if rename was blocked or unblocking before. | |
| // If it still needs to block, the blocking should happen the next | |
| // cycle and there should be space to hold everything due to the squash. | |
| if (renameStatus[tid] == Blocked || | |
| renameStatus[tid] == Unblocking) { | |
| toDecode->renameUnblock[tid] = 1; | |
| resumeSerialize = false; | |
| serializeInst[tid] = NULL; | |
| } else if (renameStatus[tid] == SerializeStall) { | |
| if (serializeInst[tid]->seqNum <= squash_seq_num) { | |
| DPRINTF(Rename, "Rename will resume serializing after squash\n"); | |
| resumeSerialize = true; | |
| assert(serializeInst[tid]); | |
| } else { | |
| resumeSerialize = false; | |
| toDecode->renameUnblock[tid] = 1; | |
| serializeInst[tid] = NULL; | |
| } | |
| } | |
| // Set the status to Squashing. | |
| renameStatus[tid] = Squashing; | |
| // Squash any instructions from decode. | |
| for (int i=0; i<fromDecode->size; i++) { | |
| if (fromDecode->insts[i]->threadNumber == tid && | |
| fromDecode->insts[i]->seqNum > squash_seq_num) { | |
| fromDecode->insts[i]->setSquashed(); | |
| wroteToTimeBuffer = true; | |
| } | |
| } | |
| // Clear the instruction list and skid buffer in case they have any | |
| // insts in them. | |
| insts[tid].clear(); | |
| // Clear the skid buffer in case it has any data in it. | |
| skidBuffer[tid].clear(); | |
| doSquash(squash_seq_num, tid); | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::tick() | |
| { | |
| wroteToTimeBuffer = false; | |
| blockThisCycle = false; | |
| bool status_change = false; | |
| toIEWIndex = 0; | |
| sortInsts(); | |
| list<ThreadID>::iterator threads = activeThreads->begin(); | |
| list<ThreadID>::iterator end = activeThreads->end(); | |
| // Check stall and squash signals. | |
| while (threads != end) { | |
| ThreadID tid = *threads++; | |
| DPRINTF(Rename, "Processing [tid:%i]\n", tid); | |
| status_change = checkSignalsAndUpdate(tid) || status_change; | |
| rename(status_change, tid); | |
| } | |
| if (status_change) { | |
| updateStatus(); | |
| } | |
| if (wroteToTimeBuffer) { | |
| DPRINTF(Activity, "Activity this cycle.\n"); | |
| cpu->activityThisCycle(); | |
| } | |
| threads = activeThreads->begin(); | |
| while (threads != end) { | |
| ThreadID tid = *threads++; | |
| // If we committed this cycle then doneSeqNum will be > 0 | |
| if (fromCommit->commitInfo[tid].doneSeqNum != 0 && | |
| !fromCommit->commitInfo[tid].squash && | |
| renameStatus[tid] != Squashing) { | |
| removeFromHistory(fromCommit->commitInfo[tid].doneSeqNum, | |
| tid); | |
| } | |
| } | |
| // @todo: make into updateProgress function | |
| for (ThreadID tid = 0; tid < numThreads; tid++) { | |
| instsInProgress[tid] -= fromIEW->iewInfo[tid].dispatched; | |
| loadsInProgress[tid] -= fromIEW->iewInfo[tid].dispatchedToLQ; | |
| storesInProgress[tid] -= fromIEW->iewInfo[tid].dispatchedToSQ; | |
| assert(loadsInProgress[tid] >= 0); | |
| assert(storesInProgress[tid] >= 0); | |
| assert(instsInProgress[tid] >=0); | |
| } | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::rename(bool &status_change, ThreadID tid) | |
| { | |
| // If status is Running or idle, | |
| // call renameInsts() | |
| // If status is Unblocking, | |
| // buffer any instructions coming from decode | |
| // continue trying to empty skid buffer | |
| // check if stall conditions have passed | |
| if (renameStatus[tid] == Blocked) { | |
| ++renameBlockCycles; | |
| } else if (renameStatus[tid] == Squashing) { | |
| ++renameSquashCycles; | |
| } else if (renameStatus[tid] == SerializeStall) { | |
| ++renameSerializeStallCycles; | |
| // If we are currently in SerializeStall and resumeSerialize | |
| // was set, then that means that we are resuming serializing | |
| // this cycle. Tell the previous stages to block. | |
| if (resumeSerialize) { | |
| resumeSerialize = false; | |
| block(tid); | |
| toDecode->renameUnblock[tid] = false; | |
| } | |
| } else if (renameStatus[tid] == Unblocking) { | |
| if (resumeUnblocking) { | |
| block(tid); | |
| resumeUnblocking = false; | |
| toDecode->renameUnblock[tid] = false; | |
| } | |
| } | |
| if (renameStatus[tid] == Running || | |
| renameStatus[tid] == Idle) { | |
| DPRINTF(Rename, "[tid:%u]: Not blocked, so attempting to run " | |
| "stage.\n", tid); | |
| renameInsts(tid); | |
| } else if (renameStatus[tid] == Unblocking) { | |
| renameInsts(tid); | |
| if (validInsts()) { | |
| // Add the current inputs to the skid buffer so they can be | |
| // reprocessed when this stage unblocks. | |
| skidInsert(tid); | |
| } | |
| // If we switched over to blocking, then there's a potential for | |
| // an overall status change. | |
| status_change = unblock(tid) || status_change || blockThisCycle; | |
| } | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::renameInsts(ThreadID tid) | |
| { | |
| // Instructions can be either in the skid buffer or the queue of | |
| // instructions coming from decode, depending on the status. | |
| int insts_available = renameStatus[tid] == Unblocking ? | |
| skidBuffer[tid].size() : insts[tid].size(); | |
| // Check the decode queue to see if instructions are available. | |
| // If there are no available instructions to rename, then do nothing. | |
| if (insts_available == 0) { | |
| DPRINTF(Rename, "[tid:%u]: Nothing to do, breaking out early.\n", | |
| tid); | |
| // Should I change status to idle? | |
| ++renameIdleCycles; | |
| return; | |
| } else if (renameStatus[tid] == Unblocking) { | |
| ++renameUnblockCycles; | |
| } else if (renameStatus[tid] == Running) { | |
| ++renameRunCycles; | |
| } | |
| DynInstPtr inst; | |
| // Will have to do a different calculation for the number of free | |
| // entries. | |
| int free_rob_entries = calcFreeROBEntries(tid); | |
| int free_iq_entries = calcFreeIQEntries(tid); | |
| int min_free_entries = free_rob_entries; | |
| FullSource source = ROB; | |
| if (free_iq_entries < min_free_entries) { | |
| min_free_entries = free_iq_entries; | |
| source = IQ; | |
| } | |
| // Check if there's any space left. | |
| if (min_free_entries <= 0) { | |
| DPRINTF(Rename, "[tid:%u]: Blocking due to no free ROB/IQ/ " | |
| "entries.\n" | |
| "ROB has %i free entries.\n" | |
| "IQ has %i free entries.\n", | |
| tid, | |
| free_rob_entries, | |
| free_iq_entries); | |
| blockThisCycle = true; | |
| block(tid); | |
| incrFullStat(source); | |
| return; | |
| } else if (min_free_entries < insts_available) { | |
| DPRINTF(Rename, "[tid:%u]: Will have to block this cycle." | |
| "%i insts available, but only %i insts can be " | |
| "renamed due to ROB/IQ/LSQ limits.\n", | |
| tid, insts_available, min_free_entries); | |
| insts_available = min_free_entries; | |
| blockThisCycle = true; | |
| incrFullStat(source); | |
| } | |
| InstQueue &insts_to_rename = renameStatus[tid] == Unblocking ? | |
| skidBuffer[tid] : insts[tid]; | |
| DPRINTF(Rename, "[tid:%u]: %i available instructions to " | |
| "send iew.\n", tid, insts_available); | |
| DPRINTF(Rename, "[tid:%u]: %i insts pipelining from Rename | %i insts " | |
| "dispatched to IQ last cycle.\n", | |
| tid, instsInProgress[tid], fromIEW->iewInfo[tid].dispatched); | |
| // Handle serializing the next instruction if necessary. | |
| if (serializeOnNextInst[tid]) { | |
| if (emptyROB[tid] && instsInProgress[tid] == 0) { | |
| // ROB already empty; no need to serialize. | |
| serializeOnNextInst[tid] = false; | |
| } else if (!insts_to_rename.empty()) { | |
| insts_to_rename.front()->setSerializeBefore(); | |
| } | |
| } | |
| int renamed_insts = 0; | |
| while (insts_available > 0 && toIEWIndex < renameWidth) { | |
| DPRINTF(Rename, "[tid:%u]: Sending instructions to IEW.\n", tid); | |
| assert(!insts_to_rename.empty()); | |
| inst = insts_to_rename.front(); | |
| //For all kind of instructions, check ROB and IQ first | |
| //For load instruction, check LQ size and take into account the inflight loads | |
| //For store instruction, check SQ size and take into account the inflight stores | |
| if (inst->isLoad()) { | |
| if(calcFreeLQEntries(tid) <= 0) { | |
| DPRINTF(Rename, "[tid:%u]: Cannot rename due to no free LQ\n"); | |
| source = LQ; | |
| incrFullStat(source); | |
| break; | |
| } | |
| } | |
| if (inst->isStore()) { | |
| if(calcFreeSQEntries(tid) <= 0) { | |
| DPRINTF(Rename, "[tid:%u]: Cannot rename due to no free SQ\n"); | |
| source = SQ; | |
| incrFullStat(source); | |
| break; | |
| } | |
| } | |
| insts_to_rename.pop_front(); | |
| if (renameStatus[tid] == Unblocking) { | |
| DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%s from rename " | |
| "skidBuffer\n", tid, inst->seqNum, inst->pcState()); | |
| } | |
| if (inst->isSquashed()) { | |
| DPRINTF(Rename, "[tid:%u]: instruction %i with PC %s is " | |
| "squashed, skipping.\n", tid, inst->seqNum, | |
| inst->pcState()); | |
| ++renameSquashedInsts; | |
| // Decrement how many instructions are available. | |
| --insts_available; | |
| continue; | |
| } | |
| DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with " | |
| "PC %s.\n", tid, inst->seqNum, inst->pcState()); | |
| // Check here to make sure there are enough destination registers | |
| // to rename to. Otherwise block. | |
| if (renameMap[tid]->numFreeEntries() < inst->numDestRegs()) { | |
| DPRINTF(Rename, "Blocking due to lack of free " | |
| "physical registers to rename to.\n"); | |
| blockThisCycle = true; | |
| insts_to_rename.push_front(inst); | |
| ++renameFullRegistersEvents; | |
| break; | |
| } | |
| // Handle serializeAfter/serializeBefore instructions. | |
| // serializeAfter marks the next instruction as serializeBefore. | |
| // serializeBefore makes the instruction wait in rename until the ROB | |
| // is empty. | |
| // In this model, IPR accesses are serialize before | |
| // instructions, and store conditionals are serialize after | |
| // instructions. This is mainly due to lack of support for | |
| // out-of-order operations of either of those classes of | |
| // instructions. | |
| if ((inst->isIprAccess() || inst->isSerializeBefore()) && | |
| !inst->isSerializeHandled()) { | |
| DPRINTF(Rename, "Serialize before instruction encountered.\n"); | |
| if (!inst->isTempSerializeBefore()) { | |
| renamedSerializing++; | |
| inst->setSerializeHandled(); | |
| } else { | |
| renamedTempSerializing++; | |
| } | |
| // Change status over to SerializeStall so that other stages know | |
| // what this is blocked on. | |
| renameStatus[tid] = SerializeStall; | |
| serializeInst[tid] = inst; | |
| blockThisCycle = true; | |
| break; | |
| } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) && | |
| !inst->isSerializeHandled()) { | |
| DPRINTF(Rename, "Serialize after instruction encountered.\n"); | |
| renamedSerializing++; | |
| inst->setSerializeHandled(); | |
| serializeAfter(insts_to_rename, tid); | |
| } | |
| renameSrcRegs(inst, inst->threadNumber); | |
| renameDestRegs(inst, inst->threadNumber); | |
| if (inst->isLoad()) { | |
| loadsInProgress[tid]++; | |
| } | |
| if (inst->isStore()) { | |
| storesInProgress[tid]++; | |
| } | |
| ++renamed_insts; | |
| // Put instruction in rename queue. | |
| toIEW->insts[toIEWIndex] = inst; | |
| ++(toIEW->size); | |
| // Increment which instruction we're on. | |
| ++toIEWIndex; | |
| // Decrement how many instructions are available. | |
| --insts_available; | |
| } | |
| instsInProgress[tid] += renamed_insts; | |
| renameRenamedInsts += renamed_insts; | |
| // If we wrote to the time buffer, record this. | |
| if (toIEWIndex) { | |
| wroteToTimeBuffer = true; | |
| } | |
| // Check if there's any instructions left that haven't yet been renamed. | |
| // If so then block. | |
| if (insts_available) { | |
| blockThisCycle = true; | |
| } | |
| if (blockThisCycle) { | |
| block(tid); | |
| toDecode->renameUnblock[tid] = false; | |
| } | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::skidInsert(ThreadID tid) | |
| { | |
| DynInstPtr inst = NULL; | |
| while (!insts[tid].empty()) { | |
| inst = insts[tid].front(); | |
| insts[tid].pop_front(); | |
| assert(tid == inst->threadNumber); | |
| DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC: %s into Rename " | |
| "skidBuffer\n", tid, inst->seqNum, inst->pcState()); | |
| ++renameSkidInsts; | |
| skidBuffer[tid].push_back(inst); | |
| } | |
| if (skidBuffer[tid].size() > skidBufferMax) | |
| { | |
| typename InstQueue::iterator it; | |
| warn("Skidbuffer contents:\n"); | |
| for(it = skidBuffer[tid].begin(); it != skidBuffer[tid].end(); it++) | |
| { | |
| warn("[tid:%u]: %s [sn:%i].\n", tid, | |
| (*it)->staticInst->disassemble(inst->instAddr()), | |
| (*it)->seqNum); | |
| } | |
| panic("Skidbuffer Exceeded Max Size"); | |
| } | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::sortInsts() | |
| { | |
| int insts_from_decode = fromDecode->size; | |
| for (int i = 0; i < insts_from_decode; ++i) { | |
| DynInstPtr inst = fromDecode->insts[i]; | |
| insts[inst->threadNumber].push_back(inst); | |
| #if TRACING_ON | |
| if (DTRACE(O3PipeView)) { | |
| inst->renameTick = curTick() - inst->fetchTick; | |
| } | |
| #endif | |
| } | |
| } | |
| template<class Impl> | |
| bool | |
| DefaultRename<Impl>::skidsEmpty() | |
| { | |
| list<ThreadID>::iterator threads = activeThreads->begin(); | |
| list<ThreadID>::iterator end = activeThreads->end(); | |
| while (threads != end) { | |
| ThreadID tid = *threads++; | |
| if (!skidBuffer[tid].empty()) | |
| return false; | |
| } | |
| return true; | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::updateStatus() | |
| { | |
| bool any_unblocking = false; | |
| list<ThreadID>::iterator threads = activeThreads->begin(); | |
| list<ThreadID>::iterator end = activeThreads->end(); | |
| while (threads != end) { | |
| ThreadID tid = *threads++; | |
| if (renameStatus[tid] == Unblocking) { | |
| any_unblocking = true; | |
| break; | |
| } | |
| } | |
| // Rename will have activity if it's unblocking. | |
| if (any_unblocking) { | |
| if (_status == Inactive) { | |
| _status = Active; | |
| DPRINTF(Activity, "Activating stage.\n"); | |
| cpu->activateStage(O3CPU::RenameIdx); | |
| } | |
| } else { | |
| // If it's not unblocking, then rename will not have any internal | |
| // activity. Switch it to inactive. | |
| if (_status == Active) { | |
| _status = Inactive; | |
| DPRINTF(Activity, "Deactivating stage.\n"); | |
| cpu->deactivateStage(O3CPU::RenameIdx); | |
| } | |
| } | |
| } | |
| template <class Impl> | |
| bool | |
| DefaultRename<Impl>::block(ThreadID tid) | |
| { | |
| DPRINTF(Rename, "[tid:%u]: Blocking.\n", tid); | |
| // Add the current inputs onto the skid buffer, so they can be | |
| // reprocessed when this stage unblocks. | |
| skidInsert(tid); | |
| // Only signal backwards to block if the previous stages do not think | |
| // rename is already blocked. | |
| if (renameStatus[tid] != Blocked) { | |
| // If resumeUnblocking is set, we unblocked during the squash, | |
| // but now we're have unblocking status. We need to tell earlier | |
| // stages to block. | |
| if (resumeUnblocking || renameStatus[tid] != Unblocking) { | |
| toDecode->renameBlock[tid] = true; | |
| toDecode->renameUnblock[tid] = false; | |
| wroteToTimeBuffer = true; | |
| } | |
| // Rename can not go from SerializeStall to Blocked, otherwise | |
| // it would not know to complete the serialize stall. | |
| if (renameStatus[tid] != SerializeStall) { | |
| // Set status to Blocked. | |
| renameStatus[tid] = Blocked; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| template <class Impl> | |
| bool | |
| DefaultRename<Impl>::unblock(ThreadID tid) | |
| { | |
| DPRINTF(Rename, "[tid:%u]: Trying to unblock.\n", tid); | |
| // Rename is done unblocking if the skid buffer is empty. | |
| if (skidBuffer[tid].empty() && renameStatus[tid] != SerializeStall) { | |
| DPRINTF(Rename, "[tid:%u]: Done unblocking.\n", tid); | |
| toDecode->renameUnblock[tid] = true; | |
| wroteToTimeBuffer = true; | |
| renameStatus[tid] = Running; | |
| return true; | |
| } | |
| return false; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::doSquash(const InstSeqNum &squashed_seq_num, ThreadID tid) | |
| { | |
| typename std::list<RenameHistory>::iterator hb_it = | |
| historyBuffer[tid].begin(); | |
| // After a syscall squashes everything, the history buffer may be empty | |
| // but the ROB may still be squashing instructions. | |
| if (historyBuffer[tid].empty()) { | |
| return; | |
| } | |
| // Go through the most recent instructions, undoing the mappings | |
| // they did and freeing up the registers. | |
| while (!historyBuffer[tid].empty() && | |
| hb_it->instSeqNum > squashed_seq_num) { | |
| assert(hb_it != historyBuffer[tid].end()); | |
| DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " | |
| "number %i.\n", tid, hb_it->instSeqNum); | |
| // Undo the rename mapping only if it was really a change. | |
| // Special regs that are not really renamed (like misc regs | |
| // and the zero reg) can be recognized because the new mapping | |
| // is the same as the old one. While it would be merely a | |
| // waste of time to update the rename table, we definitely | |
| // don't want to put these on the free list. | |
| if (hb_it->newPhysReg != hb_it->prevPhysReg) { | |
| // Tell the rename map to set the architected register to the | |
| // previous physical register that it was renamed to. | |
| renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg); | |
| // Put the renamed physical register back on the free list. | |
| freeList->addReg(hb_it->newPhysReg); | |
| } | |
| historyBuffer[tid].erase(hb_it++); | |
| ++renameUndoneMaps; | |
| } | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num, ThreadID tid) | |
| { | |
| DPRINTF(Rename, "[tid:%u]: Removing a committed instruction from the " | |
| "history buffer %u (size=%i), until [sn:%lli].\n", | |
| tid, tid, historyBuffer[tid].size(), inst_seq_num); | |
| typename std::list<RenameHistory>::iterator hb_it = | |
| historyBuffer[tid].end(); | |
| --hb_it; | |
| if (historyBuffer[tid].empty()) { | |
| DPRINTF(Rename, "[tid:%u]: History buffer is empty.\n", tid); | |
| return; | |
| } else if (hb_it->instSeqNum > inst_seq_num) { | |
| DPRINTF(Rename, "[tid:%u]: Old sequence number encountered. Ensure " | |
| "that a syscall happened recently.\n", tid); | |
| return; | |
| } | |
| // Commit all the renames up until (and including) the committed sequence | |
| // number. Some or even all of the committed instructions may not have | |
| // rename histories if they did not have destination registers that were | |
| // renamed. | |
| while (!historyBuffer[tid].empty() && | |
| hb_it != historyBuffer[tid].end() && | |
| hb_it->instSeqNum <= inst_seq_num) { | |
| DPRINTF(Rename, "[tid:%u]: Freeing up older rename of reg %i, " | |
| "[sn:%lli].\n", | |
| tid, hb_it->prevPhysReg, hb_it->instSeqNum); | |
| // Don't free special phys regs like misc and zero regs, which | |
| // can be recognized because the new mapping is the same as | |
| // the old one. | |
| if (hb_it->newPhysReg != hb_it->prevPhysReg) { | |
| freeList->addReg(hb_it->prevPhysReg); | |
| } | |
| ++renameCommittedMaps; | |
| historyBuffer[tid].erase(hb_it--); | |
| } | |
| } | |
| template <class Impl> | |
| inline void | |
| DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst, ThreadID tid) | |
| { | |
| ThreadContext *tc = inst->tcBase(); | |
| RenameMap *map = renameMap[tid]; | |
| unsigned num_src_regs = inst->numSrcRegs(); | |
| // Get the architectual register numbers from the source and | |
| // operands, and redirect them to the right physical register. | |
| for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { | |
| RegIndex src_reg = inst->srcRegIdx(src_idx); | |
| RegIndex rel_src_reg; | |
| RegIndex flat_rel_src_reg; | |
| PhysRegIndex renamed_reg; | |
| switch (regIdxToClass(src_reg, &rel_src_reg)) { | |
| case IntRegClass: | |
| flat_rel_src_reg = tc->flattenIntIndex(rel_src_reg); | |
| renamed_reg = map->lookupInt(flat_rel_src_reg); | |
| intRenameLookups++; | |
| break; | |
| case FloatRegClass: | |
| flat_rel_src_reg = tc->flattenFloatIndex(rel_src_reg); | |
| renamed_reg = map->lookupFloat(flat_rel_src_reg); | |
| fpRenameLookups++; | |
| break; | |
| case CCRegClass: | |
| flat_rel_src_reg = tc->flattenCCIndex(rel_src_reg); | |
| renamed_reg = map->lookupCC(flat_rel_src_reg); | |
| break; | |
| case MiscRegClass: | |
| // misc regs don't get flattened | |
| flat_rel_src_reg = rel_src_reg; | |
| renamed_reg = map->lookupMisc(flat_rel_src_reg); | |
| break; | |
| default: | |
| panic("Reg index is out of bound: %d.", src_reg); | |
| } | |
| DPRINTF(Rename, "[tid:%u]: Looking up %s arch reg %i (flattened %i), " | |
| "got phys reg %i\n", tid, RegClassStrings[regIdxToClass(src_reg)], | |
| (int)src_reg, (int)flat_rel_src_reg, (int)renamed_reg); | |
| inst->renameSrcReg(src_idx, renamed_reg); | |
| // See if the register is ready or not. | |
| if (scoreboard->getReg(renamed_reg)) { | |
| DPRINTF(Rename, "[tid:%u]: Register %d is ready.\n", | |
| tid, renamed_reg); | |
| inst->markSrcRegReady(src_idx); | |
| } else { | |
| DPRINTF(Rename, "[tid:%u]: Register %d is not ready.\n", | |
| tid, renamed_reg); | |
| } | |
| ++renameRenameLookups; | |
| } | |
| } | |
| template <class Impl> | |
| inline void | |
| DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst, ThreadID tid) | |
| { | |
| ThreadContext *tc = inst->tcBase(); | |
| RenameMap *map = renameMap[tid]; | |
| unsigned num_dest_regs = inst->numDestRegs(); | |
| // Rename the destination registers. | |
| for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { | |
| RegIndex dest_reg = inst->destRegIdx(dest_idx); | |
| RegIndex rel_dest_reg; | |
| RegIndex flat_rel_dest_reg; | |
| RegIndex flat_uni_dest_reg; | |
| typename RenameMap::RenameInfo rename_result; | |
| switch (regIdxToClass(dest_reg, &rel_dest_reg)) { | |
| case IntRegClass: | |
| flat_rel_dest_reg = tc->flattenIntIndex(rel_dest_reg); | |
| rename_result = map->renameInt(flat_rel_dest_reg); | |
| flat_uni_dest_reg = flat_rel_dest_reg; // 1:1 mapping | |
| break; | |
| case FloatRegClass: | |
| flat_rel_dest_reg = tc->flattenFloatIndex(rel_dest_reg); | |
| rename_result = map->renameFloat(flat_rel_dest_reg); | |
| flat_uni_dest_reg = flat_rel_dest_reg + TheISA::FP_Reg_Base; | |
| break; | |
| case CCRegClass: | |
| flat_rel_dest_reg = tc->flattenCCIndex(rel_dest_reg); | |
| rename_result = map->renameCC(flat_rel_dest_reg); | |
| flat_uni_dest_reg = flat_rel_dest_reg + TheISA::CC_Reg_Base; | |
| break; | |
| case MiscRegClass: | |
| // misc regs don't get flattened | |
| flat_rel_dest_reg = rel_dest_reg; | |
| rename_result = map->renameMisc(flat_rel_dest_reg); | |
| flat_uni_dest_reg = flat_rel_dest_reg + TheISA::Misc_Reg_Base; | |
| break; | |
| default: | |
| panic("Reg index is out of bound: %d.", dest_reg); | |
| } | |
| inst->flattenDestReg(dest_idx, flat_uni_dest_reg); | |
| // Mark Scoreboard entry as not ready | |
| scoreboard->unsetReg(rename_result.first); | |
| DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " | |
| "reg %i.\n", tid, (int)flat_rel_dest_reg, | |
| (int)rename_result.first); | |
| // Record the rename information so that a history can be kept. | |
| RenameHistory hb_entry(inst->seqNum, flat_uni_dest_reg, | |
| rename_result.first, | |
| rename_result.second); | |
| historyBuffer[tid].push_front(hb_entry); | |
| DPRINTF(Rename, "[tid:%u]: Adding instruction to history buffer " | |
| "(size=%i), [sn:%lli].\n",tid, | |
| historyBuffer[tid].size(), | |
| (*historyBuffer[tid].begin()).instSeqNum); | |
| // Tell the instruction to rename the appropriate destination | |
| // register (dest_idx) to the new physical register | |
| // (rename_result.first), and record the previous physical | |
| // register that the same logical register was renamed to | |
| // (rename_result.second). | |
| inst->renameDestReg(dest_idx, | |
| rename_result.first, | |
| rename_result.second); | |
| ++renameRenamedOperands; | |
| } | |
| } | |
| template <class Impl> | |
| inline int | |
| DefaultRename<Impl>::calcFreeROBEntries(ThreadID tid) | |
| { | |
| int num_free = freeEntries[tid].robEntries - | |
| (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); | |
| //DPRINTF(Rename,"[tid:%i]: %i rob free\n",tid,num_free); | |
| return num_free; | |
| } | |
| template <class Impl> | |
| inline int | |
| DefaultRename<Impl>::calcFreeIQEntries(ThreadID tid) | |
| { | |
| int num_free = freeEntries[tid].iqEntries - | |
| (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); | |
| //DPRINTF(Rename,"[tid:%i]: %i iq free\n",tid,num_free); | |
| return num_free; | |
| } | |
| template <class Impl> | |
| inline int | |
| DefaultRename<Impl>::calcFreeLQEntries(ThreadID tid) | |
| { | |
| int num_free = freeEntries[tid].lqEntries - | |
| (loadsInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToLQ); | |
| DPRINTF(Rename, "calcFreeLQEntries: free lqEntries: %d, loadsInProgress: %d, " | |
| "loads dispatchedToLQ: %d\n", freeEntries[tid].lqEntries, | |
| loadsInProgress[tid], fromIEW->iewInfo[tid].dispatchedToLQ); | |
| return num_free; | |
| } | |
| template <class Impl> | |
| inline int | |
| DefaultRename<Impl>::calcFreeSQEntries(ThreadID tid) | |
| { | |
| int num_free = freeEntries[tid].sqEntries - | |
| (storesInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToSQ); | |
| DPRINTF(Rename, "calcFreeSQEntries: free sqEntries: %d, storesInProgress: %d, " | |
| "stores dispatchedToSQ: %d\n", freeEntries[tid].sqEntries, | |
| storesInProgress[tid], fromIEW->iewInfo[tid].dispatchedToSQ); | |
| return num_free; | |
| } | |
| template <class Impl> | |
| unsigned | |
| DefaultRename<Impl>::validInsts() | |
| { | |
| unsigned inst_count = 0; | |
| for (int i=0; i<fromDecode->size; i++) { | |
| if (!fromDecode->insts[i]->isSquashed()) | |
| inst_count++; | |
| } | |
| return inst_count; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::readStallSignals(ThreadID tid) | |
| { | |
| if (fromIEW->iewBlock[tid]) { | |
| stalls[tid].iew = true; | |
| } | |
| if (fromIEW->iewUnblock[tid]) { | |
| assert(stalls[tid].iew); | |
| stalls[tid].iew = false; | |
| } | |
| } | |
| template <class Impl> | |
| bool | |
| DefaultRename<Impl>::checkStall(ThreadID tid) | |
| { | |
| bool ret_val = false; | |
| if (stalls[tid].iew) { | |
| DPRINTF(Rename,"[tid:%i]: Stall from IEW stage detected.\n", tid); | |
| ret_val = true; | |
| } else if (calcFreeROBEntries(tid) <= 0) { | |
| DPRINTF(Rename,"[tid:%i]: Stall: ROB has 0 free entries.\n", tid); | |
| ret_val = true; | |
| } else if (calcFreeIQEntries(tid) <= 0) { | |
| DPRINTF(Rename,"[tid:%i]: Stall: IQ has 0 free entries.\n", tid); | |
| ret_val = true; | |
| } else if (calcFreeLQEntries(tid) <= 0 && calcFreeSQEntries(tid) <= 0) { | |
| DPRINTF(Rename,"[tid:%i]: Stall: LSQ has 0 free entries.\n", tid); | |
| ret_val = true; | |
| } else if (renameMap[tid]->numFreeEntries() <= 0) { | |
| DPRINTF(Rename,"[tid:%i]: Stall: RenameMap has 0 free entries.\n", tid); | |
| ret_val = true; | |
| } else if (renameStatus[tid] == SerializeStall && | |
| (!emptyROB[tid] || instsInProgress[tid])) { | |
| DPRINTF(Rename,"[tid:%i]: Stall: Serialize stall and ROB is not " | |
| "empty.\n", | |
| tid); | |
| ret_val = true; | |
| } | |
| return ret_val; | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::readFreeEntries(ThreadID tid) | |
| { | |
| if (fromIEW->iewInfo[tid].usedIQ) | |
| freeEntries[tid].iqEntries = fromIEW->iewInfo[tid].freeIQEntries; | |
| if (fromIEW->iewInfo[tid].usedLSQ) { | |
| freeEntries[tid].lqEntries = fromIEW->iewInfo[tid].freeLQEntries; | |
| freeEntries[tid].sqEntries = fromIEW->iewInfo[tid].freeSQEntries; | |
| } | |
| if (fromCommit->commitInfo[tid].usedROB) { | |
| freeEntries[tid].robEntries = | |
| fromCommit->commitInfo[tid].freeROBEntries; | |
| emptyROB[tid] = fromCommit->commitInfo[tid].emptyROB; | |
| } | |
| DPRINTF(Rename, "[tid:%i]: Free IQ: %i, Free ROB: %i, " | |
| "Free LQ: %i, Free SQ: %i\n", | |
| tid, | |
| freeEntries[tid].iqEntries, | |
| freeEntries[tid].robEntries, | |
| freeEntries[tid].lqEntries, | |
| freeEntries[tid].sqEntries); | |
| DPRINTF(Rename, "[tid:%i]: %i instructions not yet in ROB\n", | |
| tid, instsInProgress[tid]); | |
| } | |
| template <class Impl> | |
| bool | |
| DefaultRename<Impl>::checkSignalsAndUpdate(ThreadID 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. | |
| // If status was serialize stall | |
| // check if ROB is empty and no insts are in flight to the ROB | |
| readFreeEntries(tid); | |
| readStallSignals(tid); | |
| if (fromCommit->commitInfo[tid].squash) { | |
| DPRINTF(Rename, "[tid:%u]: Squashing instructions due to squash from " | |
| "commit.\n", tid); | |
| squash(fromCommit->commitInfo[tid].doneSeqNum, tid); | |
| return true; | |
| } | |
| if (checkStall(tid)) { | |
| return block(tid); | |
| } | |
| if (renameStatus[tid] == Blocked) { | |
| DPRINTF(Rename, "[tid:%u]: Done blocking, switching to unblocking.\n", | |
| tid); | |
| renameStatus[tid] = Unblocking; | |
| unblock(tid); | |
| return true; | |
| } | |
| if (renameStatus[tid] == Squashing) { | |
| // Switch status to running if rename isn't being told to block or | |
| // squash this cycle. | |
| if (resumeSerialize) { | |
| DPRINTF(Rename, "[tid:%u]: Done squashing, switching to serialize.\n", | |
| tid); | |
| renameStatus[tid] = SerializeStall; | |
| return true; | |
| } else if (resumeUnblocking) { | |
| DPRINTF(Rename, "[tid:%u]: Done squashing, switching to unblocking.\n", | |
| tid); | |
| renameStatus[tid] = Unblocking; | |
| return true; | |
| } else { | |
| DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", | |
| tid); | |
| renameStatus[tid] = Running; | |
| return false; | |
| } | |
| } | |
| if (renameStatus[tid] == SerializeStall) { | |
| // Stall ends once the ROB is free. | |
| DPRINTF(Rename, "[tid:%u]: Done with serialize stall, switching to " | |
| "unblocking.\n", tid); | |
| DynInstPtr serial_inst = serializeInst[tid]; | |
| renameStatus[tid] = Unblocking; | |
| unblock(tid); | |
| DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with " | |
| "PC %s.\n", tid, serial_inst->seqNum, serial_inst->pcState()); | |
| // Put instruction into queue here. | |
| serial_inst->clearSerializeBefore(); | |
| if (!skidBuffer[tid].empty()) { | |
| skidBuffer[tid].push_front(serial_inst); | |
| } else { | |
| insts[tid].push_front(serial_inst); | |
| } | |
| DPRINTF(Rename, "[tid:%u]: Instruction must be processed by rename." | |
| " Adding to front of list.\n", tid); | |
| serializeInst[tid] = NULL; | |
| return true; | |
| } | |
| // If we've reached this point, we have not gotten any signals that | |
| // cause rename to change its status. Rename remains the same as before. | |
| return false; | |
| } | |
| template<class Impl> | |
| void | |
| DefaultRename<Impl>::serializeAfter(InstQueue &inst_list, ThreadID tid) | |
| { | |
| if (inst_list.empty()) { | |
| // Mark a bit to say that I must serialize on the next instruction. | |
| serializeOnNextInst[tid] = true; | |
| return; | |
| } | |
| // Set the next instruction as serializing. | |
| inst_list.front()->setSerializeBefore(); | |
| } | |
| template <class Impl> | |
| inline void | |
| DefaultRename<Impl>::incrFullStat(const FullSource &source) | |
| { | |
| switch (source) { | |
| case ROB: | |
| ++renameROBFullEvents; | |
| break; | |
| case IQ: | |
| ++renameIQFullEvents; | |
| break; | |
| case LQ: | |
| ++renameLQFullEvents; | |
| break; | |
| case SQ: | |
| ++renameSQFullEvents; | |
| break; | |
| default: | |
| panic("Rename full stall stat should be incremented for a reason!"); | |
| break; | |
| } | |
| } | |
| template <class Impl> | |
| void | |
| DefaultRename<Impl>::dumpHistory() | |
| { | |
| typename std::list<RenameHistory>::iterator buf_it; | |
| for (ThreadID tid = 0; tid < numThreads; tid++) { | |
| buf_it = historyBuffer[tid].begin(); | |
| while (buf_it != historyBuffer[tid].end()) { | |
| cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys " | |
| "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg, | |
| (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg); | |
| buf_it++; | |
| } | |
| } | |
| } | |
| #endif//__CPU_O3_RENAME_IMPL_HH__ |