diff options
Diffstat (limited to 'src/cpu/o3/rename_impl.hh')
-rw-r--r-- | src/cpu/o3/rename_impl.hh | 1437 |
1 files changed, 981 insertions, 456 deletions
diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index 2068b36ab..b4f1077d1 100644 --- a/src/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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 @@ -31,97 +31,146 @@ #include "config/full_system.hh" #include "cpu/o3/rename.hh" +using namespace std; + +template <class Impl> +DefaultRename<Impl>::DefaultRename(Params *params) + : iewToRenameDelay(params->iewToRenameDelay), + decodeToRenameDelay(params->decodeToRenameDelay), + commitToRenameDelay(params->commitToRenameDelay), + renameWidth(params->renameWidth), + commitWidth(params->commitWidth), + numThreads(params->numberOfThreads) +{ + _status = Inactive; + + for (int i=0; i< numThreads; i++) { + renameStatus[i] = Idle; + + freeEntries[i].iqEntries = 0; + freeEntries[i].lsqEntries = 0; + freeEntries[i].robEntries = 0; + + stalls[i].iew = false; + stalls[i].commit = false; + serializeInst[i] = NULL; + + instsInProgress[i] = 0; + + emptyROB[i] = true; + + serializeOnNextInst[i] = false; + } + + // @todo: Make into a parameter. + skidBufferMax = (2 * (iewToRenameDelay * params->decodeWidth)) + renameWidth; +} + template <class Impl> -SimpleRename<Impl>::SimpleRename(Params ¶ms) - : iewToRenameDelay(params.iewToRenameDelay), - decodeToRenameDelay(params.decodeToRenameDelay), - commitToRenameDelay(params.commitToRenameDelay), - renameWidth(params.renameWidth), - commitWidth(params.commitWidth), - numInst(0) +std::string +DefaultRename<Impl>::name() const { - _status = Idle; + return cpu->name() + ".rename"; } template <class Impl> void -SimpleRename<Impl>::regStats() +DefaultRename<Impl>::regStats() { renameSquashCycles - .name(name() + ".renameSquashCycles") + .name(name() + ".RENAME:SquashCycles") .desc("Number of cycles rename is squashing") .prereq(renameSquashCycles); renameIdleCycles - .name(name() + ".renameIdleCycles") + .name(name() + ".RENAME:IdleCycles") .desc("Number of cycles rename is idle") .prereq(renameIdleCycles); renameBlockCycles - .name(name() + ".renameBlockCycles") + .name(name() + ".RENAME:BlockCycles") .desc("Number of cycles rename is blocking") .prereq(renameBlockCycles); + renameSerializeStallCycles + .name(name() + ".RENAME:serializeStallCycles") + .desc("count of cycles rename stalled for serializing inst") + .flags(Stats::total); + renameRunCycles + .name(name() + ".RENAME:RunCycles") + .desc("Number of cycles rename is running") + .prereq(renameIdleCycles); renameUnblockCycles - .name(name() + ".renameUnblockCycles") + .name(name() + ".RENAME:UnblockCycles") .desc("Number of cycles rename is unblocking") .prereq(renameUnblockCycles); renameRenamedInsts - .name(name() + ".renameRenamedInsts") + .name(name() + ".RENAME:RenamedInsts") .desc("Number of instructions processed by rename") .prereq(renameRenamedInsts); renameSquashedInsts - .name(name() + ".renameSquashedInsts") + .name(name() + ".RENAME:SquashedInsts") .desc("Number of squashed instructions processed by rename") .prereq(renameSquashedInsts); renameROBFullEvents - .name(name() + ".renameROBFullEvents") - .desc("Number of times rename has considered the ROB 'full'") + .name(name() + ".RENAME:ROBFullEvents") + .desc("Number of times rename has blocked due to ROB full") .prereq(renameROBFullEvents); renameIQFullEvents - .name(name() + ".renameIQFullEvents") - .desc("Number of times rename has considered the IQ 'full'") + .name(name() + ".RENAME:IQFullEvents") + .desc("Number of times rename has blocked due to IQ full") .prereq(renameIQFullEvents); + renameLSQFullEvents + .name(name() + ".RENAME:LSQFullEvents") + .desc("Number of times rename has blocked due to LSQ full") + .prereq(renameLSQFullEvents); renameFullRegistersEvents - .name(name() + ".renameFullRegisterEvents") + .name(name() + ".RENAME:FullRegisterEvents") .desc("Number of times there has been no free registers") .prereq(renameFullRegistersEvents); renameRenamedOperands - .name(name() + ".renameRenamedOperands") + .name(name() + ".RENAME:RenamedOperands") .desc("Number of destination operands rename has renamed") .prereq(renameRenamedOperands); renameRenameLookups - .name(name() + ".renameRenameLookups") + .name(name() + ".RENAME:RenameLookups") .desc("Number of register rename lookups that rename has made") .prereq(renameRenameLookups); - renameHBPlaceHolders - .name(name() + ".renameHBPlaceHolders") - .desc("Number of place holders added to the history buffer") - .prereq(renameHBPlaceHolders); renameCommittedMaps - .name(name() + ".renameCommittedMaps") + .name(name() + ".RENAME:CommittedMaps") .desc("Number of HB maps that are committed") .prereq(renameCommittedMaps); renameUndoneMaps - .name(name() + ".renameUndoneMaps") + .name(name() + ".RENAME:UndoneMaps") .desc("Number of HB maps that are undone due to squashing") .prereq(renameUndoneMaps); - renameValidUndoneMaps - .name(name() + ".renameValidUndoneMaps") - .desc("Number of HB maps that are undone, and are not place holders") - .prereq(renameValidUndoneMaps); + renamedSerializing + .name(name() + ".RENAME:serializingInsts") + .desc("count of serializing insts renamed") + .flags(Stats::total) + ; + renamedTempSerializing + .name(name() + ".RENAME:tempSerializingInsts") + .desc("count of temporary serializing insts renamed") + .flags(Stats::total) + ; + renameSkidInsts + .name(name() + ".RENAME:skidInsts") + .desc("count of insts added to the skid buffer") + .flags(Stats::total) + ; } template <class Impl> void -SimpleRename<Impl>::setCPU(FullCPU *cpu_ptr) +DefaultRename<Impl>::setCPU(FullCPU *cpu_ptr) { - DPRINTF(Rename, "Rename: Setting CPU pointer.\n"); + DPRINTF(Rename, "Setting CPU pointer.\n"); cpu = cpu_ptr; } template <class Impl> void -SimpleRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +DefaultRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) { - DPRINTF(Rename, "Rename: Setting time buffer pointer.\n"); + DPRINTF(Rename, "Setting time buffer pointer.\n"); timeBuffer = tb_ptr; // Setup wire to read information from time buffer, from IEW stage. @@ -136,9 +185,9 @@ SimpleRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) template <class Impl> void -SimpleRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) +DefaultRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) { - DPRINTF(Rename, "Rename: Setting rename queue pointer.\n"); + DPRINTF(Rename, "Setting rename queue pointer.\n"); renameQueue = rq_ptr; // Setup wire to write information to future stages. @@ -147,9 +196,9 @@ SimpleRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) template <class Impl> void -SimpleRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) +DefaultRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) { - DPRINTF(Rename, "Rename: Setting decode queue pointer.\n"); + DPRINTF(Rename, "Setting decode queue pointer.\n"); decodeQueue = dq_ptr; // Setup wire to get information from decode. @@ -158,214 +207,728 @@ SimpleRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) template <class Impl> void -SimpleRename<Impl>::setRenameMap(RenameMap *rm_ptr) +DefaultRename<Impl>::initStage() +{ + // Grab the number of free entries directly from the stages. + for (int tid=0; tid < numThreads; tid++) { + freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid); + freeEntries[tid].lsqEntries = iew_ptr->ldstQueue.numFreeEntries(tid); + freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid); + emptyROB[tid] = true; + } +} + +template<class Impl> +void +DefaultRename<Impl>::setActiveThreads(list<unsigned> *at_ptr) { - DPRINTF(Rename, "Rename: Setting rename map pointer.\n"); - renameMap = rm_ptr; + DPRINTF(Rename, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; } + template <class Impl> void -SimpleRename<Impl>::setFreeList(FreeList *fl_ptr) +DefaultRename<Impl>::setRenameMap(RenameMap rm_ptr[]) { - DPRINTF(Rename, "Rename: Setting free list pointer.\n"); + DPRINTF(Rename, "Setting rename map pointers.\n"); + + for (int i=0; i<numThreads; i++) { + renameMap[i] = &rm_ptr[i]; + } +} + +template <class Impl> +void +DefaultRename<Impl>::setFreeList(FreeList *fl_ptr) +{ + DPRINTF(Rename, "Setting free list pointer.\n"); freeList = fl_ptr; } +template<class Impl> +void +DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard) +{ + DPRINTF(Rename, "Setting scoreboard pointer.\n"); + scoreboard = _scoreboard; +} + template <class Impl> void -SimpleRename<Impl>::dumpHistory() +DefaultRename<Impl>::switchOut() { - typename list<RenameHistory>::iterator buf_it = historyBuffer.begin(); + cpu->signalSwitched(); +} + +template <class Impl> +void +DefaultRename<Impl>::doSwitchOut() +{ + for (int i = 0; i < numThreads; i++) { + typename list<RenameHistory>::iterator hb_it = historyBuffer[i].begin(); + + while (!historyBuffer[i].empty()) { + assert(hb_it != historyBuffer[i].end()); - while (buf_it != historyBuffer.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); + DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " + "number %i.\n", i, (*hb_it).instSeqNum); - buf_it++; + // Tell the rename map to set the architected register to the + // previous physical register that it was renamed to. + renameMap[i]->setEntry(hb_it->archReg, hb_it->prevPhysReg); + + // Put the renamed physical register back on the free list. + freeList->addReg(hb_it->newPhysReg); + + historyBuffer[i].erase(hb_it++); + } + insts[i].clear(); + skidBuffer[i].clear(); } } template <class Impl> void -SimpleRename<Impl>::block() +DefaultRename<Impl>::takeOverFrom() { - DPRINTF(Rename, "Rename: Blocking.\n"); - // Set status to Blocked. - _status = Blocked; + _status = Inactive; + initStage(); - // Add the current inputs onto the skid buffer, so they can be - // reprocessed when this stage unblocks. - skidBuffer.push(*fromDecode); + // Reset all state prior to taking over from the other CPU. + for (int i=0; i< numThreads; i++) { + renameStatus[i] = Idle; + + stalls[i].iew = false; + stalls[i].commit = false; + serializeInst[i] = NULL; + + instsInProgress[i] = 0; + + emptyROB[i] = true; - // Note that this stage only signals previous stages to stall when - // it is the cause of the stall originates at this stage. Otherwise - // the previous stages are expected to check all possible stall signals. + serializeOnNextInst[i] = false; + } } template <class Impl> -inline void -SimpleRename<Impl>::unblock() -{ - DPRINTF(Rename, "Rename: Read instructions out of skid buffer this " - "cycle.\n"); - // Remove the now processed instructions from the skid buffer. - skidBuffer.pop(); - - // If there's still information in the skid buffer, then - // continue to tell previous stages to stall. They will be - // able to restart once the skid buffer is empty. - if (!skidBuffer.empty()) { - toDecode->renameInfo.stall = true; - } else { - DPRINTF(Rename, "Rename: Done unblocking.\n"); - _status = Running; +void +DefaultRename<Impl>::squash(unsigned 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 || + renameStatus[tid] == SerializeStall) { +#if 0 + // In syscall emulation, we can have both a block and a squash due + // to a syscall in the same cycle. This would cause both signals to + // be high. This shouldn't happen in full system. + if (toDecode->renameBlock[tid]) { + toDecode->renameBlock[tid] = 0; + } else { + toDecode->renameUnblock[tid] = 1; + } +#else + toDecode->renameUnblock[tid] = 1; +#endif + serializeInst[tid] = NULL; + } + + // Set the status to Squashing. + renameStatus[tid] = Squashing; + + // Squash any instructions from decode. + unsigned squashCount = 0; + + for (int i=0; i<fromDecode->size; i++) { + if (fromDecode->insts[i]->threadNumber == tid) { + fromDecode->insts[i]->squashed = true; + wroteToTimeBuffer = true; + squashCount++; + } } + + insts[tid].clear(); + + // Clear the skid buffer in case it has any data in it. + skidBuffer[tid].clear(); + + doSquash(tid); } template <class Impl> void -SimpleRename<Impl>::doSquash() +DefaultRename<Impl>::tick() { - typename list<RenameHistory>::iterator hb_it = historyBuffer.begin(); + wroteToTimeBuffer = false; - InstSeqNum squashed_seq_num = fromCommit->commitInfo.doneSeqNum; + blockThisCycle = false; -#if FULL_SYSTEM - assert(!historyBuffer.empty()); -#else - // After a syscall squashes everything, the history buffer may be empty - // but the ROB may still be squashing instructions. - if (historyBuffer.empty()) { + bool status_change = false; + + toIEWIndex = 0; + + sortInsts(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + // Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned 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 != (*activeThreads).end()) { + unsigned 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 (int tid=0; tid < numThreads; tid++) { + instsInProgress[tid] -= fromIEW->iewInfo[tid].dispatched; + + assert(instsInProgress[tid] >=0); + } + +} + +template<class Impl> +void +DefaultRename<Impl>::rename(bool &status_change, unsigned 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 (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(unsigned 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; } -#endif // FULL_SYSTEM - // Go through the most recent instructions, undoing the mappings - // they did and freeing up the registers. - while ((*hb_it).instSeqNum > squashed_seq_num) - { - assert(hb_it != historyBuffer.end()); + DynInstPtr inst; - DPRINTF(Rename, "Rename: Removing history entry with sequence " - "number %i.\n", (*hb_it).instSeqNum); + // 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 free_lsq_entries = calcFreeLSQEntries(tid); + int min_free_entries = free_rob_entries; - // If it's not simply a place holder, then add the registers. - if (!(*hb_it).placeHolder) { - // Tell the rename map to set the architected register to the - // previous physical register that it was renamed to. - renameMap->setEntry(hb_it->archReg, hb_it->prevPhysReg); + FullSource source = ROB; - // Put the renamed physical register back on the free list. - freeList->addReg(hb_it->newPhysReg); + if (free_iq_entries < min_free_entries) { + min_free_entries = free_iq_entries; + source = IQ; + } - ++renameValidUndoneMaps; + if (free_lsq_entries < min_free_entries) { + min_free_entries = free_lsq_entries; + source = LSQ; + } + + // Check if there's any space left. + if (min_free_entries <= 0) { + DPRINTF(Rename, "[tid:%u]: Blocking due to no free ROB/IQ/LSQ " + "entries.\n" + "ROB has %i free entries.\n" + "IQ has %i free entries.\n" + "LSQ has %i free entries.\n", + tid, + free_rob_entries, + free_iq_entries, + free_lsq_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(); } + } - historyBuffer.erase(hb_it++); + int renamed_insts = 0; - ++renameUndoneMaps; + 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(); + + insts_to_rename.pop_front(); + + if (renameStatus[tid] == Unblocking) { + DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%#x from rename " + "skidBuffer\n", + tid, inst->seqNum, inst->readPC()); + } + + if (inst->isSquashed()) { + DPRINTF(Rename, "[tid:%u]: instruction %i with PC %#x is " + "squashed, skipping.\n", + tid, inst->seqNum, inst->threadNumber,inst->readPC()); + + ++renameSquashedInsts; + + // Decrement how many instructions are available. + --insts_available; + + continue; + } + + DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with " + "PC %#x.\n", + tid, inst->seqNum, inst->readPC()); + + // 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); + } + + // 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; + + ++renameFullRegistersEvents; + + break; + } + + renameSrcRegs(inst, inst->threadNumber); + + renameDestRegs(inst, inst->threadNumber); + + ++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(unsigned 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:%#x into Rename " + "skidBuffer\n", tid, inst->seqNum, inst->readPC()); + + ++renameSkidInsts; + + skidBuffer[tid].push_back(inst); + } + + if (skidBuffer[tid].size() > skidBufferMax) + panic("Skidbuffer Exceeded Max Size"); +} + template <class Impl> void -SimpleRename<Impl>::squash() +DefaultRename<Impl>::sortInsts() { - DPRINTF(Rename, "Rename: Squashing instructions.\n"); - // Set the status to Squashing. - _status = Squashing; + int insts_from_decode = fromDecode->size; +#ifdef DEBUG + for (int i=0; i < numThreads; i++) + assert(insts[i].empty()); +#endif + for (int i = 0; i < insts_from_decode; ++i) { + DynInstPtr inst = fromDecode->insts[i]; + insts[inst->threadNumber].push_back(inst); + } +} - numInst = 0; +template<class Impl> +bool +DefaultRename<Impl>::skidsEmpty() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer.empty()) - { - skidBuffer.pop(); + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; } - doSquash(); + return true; } template<class Impl> void -SimpleRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num) +DefaultRename<Impl>::updateStatus() { - DPRINTF(Rename, "Rename: Removing a committed instruction from the " - "history buffer, until sequence number %lli.\n", inst_seq_num); - typename list<RenameHistory>::iterator hb_it = historyBuffer.end(); + bool any_unblocking = false; - --hb_it; + list<unsigned>::iterator threads = (*activeThreads).begin(); - if (hb_it->instSeqNum > inst_seq_num) { - DPRINTF(Rename, "Rename: Old sequence number encountered. Ensure " - "that a syscall happened recently.\n"); - return; + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (renameStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } } - while ((*hb_it).instSeqNum != inst_seq_num) - { - // Make sure we haven't gone off the end of the list. - assert(hb_it != historyBuffer.end()); - - // In theory instructions at the end of the history buffer - // should be older than the instruction being removed, which - // means they will have a lower sequence number. Also the - // instruction being removed from the history really should - // be the last instruction in the list, as it is the instruction - // that was just committed that is being removed. - assert(hb_it->instSeqNum < inst_seq_num); - DPRINTF(Rename, "Rename: Freeing up older rename of reg %i, sequence" - " number %i.\n", - (*hb_it).prevPhysReg, (*hb_it).instSeqNum); - - if (!(*hb_it).placeHolder) { - freeList->addReg((*hb_it).prevPhysReg); - ++renameCommittedMaps; + // Rename will have activity if it's unblocking. + if (any_unblocking) { + if (_status == Inactive) { + _status = Active; + + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(FullCPU::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"); - historyBuffer.erase(hb_it--); + cpu->deactivateStage(FullCPU::RenameIdx); + } } +} - // Finally free up the previous register of the finished instruction - // itself. - if (!(*hb_it).placeHolder) { - freeList->addReg(hb_it->prevPhysReg); - ++renameCommittedMaps; +template <class Impl> +bool +DefaultRename<Impl>::block(unsigned 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 (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(unsigned 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; } - historyBuffer.erase(hb_it); + return false; +} + +template <class Impl> +void +DefaultRename<Impl>::doSquash(unsigned tid) +{ + typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].begin(); + + InstSeqNum squashed_seq_num = fromCommit->commitInfo[tid].doneSeqNum; + + // 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); + + // 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, unsigned 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 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); + + freeList->addReg((*hb_it).prevPhysReg); + ++renameCommittedMaps; + + historyBuffer[tid].erase(hb_it--); + } } template <class Impl> inline void -SimpleRename<Impl>::renameSrcRegs(DynInstPtr &inst) +DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid) { + assert(renameMap[tid] != 0); + unsigned num_src_regs = inst->numSrcRegs(); // Get the architectual register numbers from the source and // destination operands, and redirect them to the right register. // Will need to mark dependencies though. - for (int src_idx = 0; src_idx < num_src_regs; src_idx++) - { + for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { RegIndex src_reg = inst->srcRegIdx(src_idx); // Look up the source registers to get the phys. register they've // been renamed to, and set the sources to those registers. - PhysRegIndex renamed_reg = renameMap->lookup(src_reg); + PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg); - DPRINTF(Rename, "Rename: Looking up arch reg %i, got " - "physical reg %i.\n", (int)src_reg, (int)renamed_reg); + DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got " + "physical reg %i.\n", tid, (int)src_reg, + (int)renamed_reg); inst->renameSrcReg(src_idx, renamed_reg); - // Either incorporate it into the info passed back, - // or make another function call to see if that register is - // ready or not. - if (renameMap->isReady(renamed_reg)) { - DPRINTF(Rename, "Rename: Register is ready.\n"); + // See if the register is ready or not. + if (scoreboard->getReg(renamed_reg) == true) { + DPRINTF(Rename, "[tid:%u]: Register is ready.\n", tid); inst->markSrcRegReady(src_idx); } @@ -376,379 +939,341 @@ SimpleRename<Impl>::renameSrcRegs(DynInstPtr &inst) template <class Impl> inline void -SimpleRename<Impl>::renameDestRegs(DynInstPtr &inst) +DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid) { - typename SimpleRenameMap::RenameInfo rename_result; + typename RenameMap::RenameInfo rename_result; unsigned num_dest_regs = inst->numDestRegs(); - // If it's an instruction with no destination registers, then put - // a placeholder within the history buffer. It might be better - // to not put it in the history buffer at all (other than branches, - // which always need at least a place holder), and differentiate - // between instructions with and without destination registers - // when getting from commit the instructions that committed. - if (num_dest_regs == 0) { - RenameHistory hb_entry(inst->seqNum); + // Rename the destination registers. + for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { + RegIndex dest_reg = inst->destRegIdx(dest_idx); - historyBuffer.push_front(hb_entry); + // Get the physical register that the destination will be + // renamed to. + rename_result = renameMap[tid]->rename(dest_reg); - DPRINTF(Rename, "Rename: Adding placeholder instruction to " - "history buffer, sequence number %lli.\n", - inst->seqNum); + //Mark Scoreboard entry as not ready + scoreboard->unsetReg(rename_result.first); - ++renameHBPlaceHolders; - } else { + DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " + "reg %i.\n", tid, (int)dest_reg, + (int)rename_result.first); - // Rename the destination registers. - for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) - { - RegIndex dest_reg = inst->destRegIdx(dest_idx); + // Record the rename information so that a history can be kept. + RenameHistory hb_entry(inst->seqNum, dest_reg, + rename_result.first, + rename_result.second); - // Get the physical register that the destination will be - // renamed to. - rename_result = renameMap->rename(dest_reg); + historyBuffer[tid].push_front(hb_entry); - DPRINTF(Rename, "Rename: Renaming arch reg %i to physical " - "reg %i.\n", (int)dest_reg, - (int)rename_result.first); + DPRINTF(Rename, "[tid:%u]: Adding instruction to history buffer, " + "[sn:%lli].\n",tid, + (*historyBuffer[tid].begin()).instSeqNum); - // Record the rename information so that a history can be kept. - RenameHistory hb_entry(inst->seqNum, dest_reg, - rename_result.first, - rename_result.second); + // 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); - historyBuffer.push_front(hb_entry); + ++renameRenamedOperands; + } +} - DPRINTF(Rename, "Rename: Adding instruction to history buffer, " - "sequence number %lli.\n", - (*historyBuffer.begin()).instSeqNum); +template <class Impl> +inline int +DefaultRename<Impl>::calcFreeROBEntries(unsigned tid) +{ + int num_free = freeEntries[tid].robEntries - + (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); - // 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); + //DPRINTF(Rename,"[tid:%i]: %i rob free\n",tid,num_free); - ++renameRenamedOperands; - } - } + return num_free; } template <class Impl> inline int -SimpleRename<Impl>::calcFreeROBEntries() +DefaultRename<Impl>::calcFreeIQEntries(unsigned tid) { - return fromCommit->commitInfo.freeROBEntries - - renameWidth * iewToRenameDelay; + 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 -SimpleRename<Impl>::calcFreeIQEntries() +DefaultRename<Impl>::calcFreeLSQEntries(unsigned tid) { - return fromIEW->iewInfo.freeIQEntries - renameWidth * iewToRenameDelay; -} + int num_free = freeEntries[tid].lsqEntries - + (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToLSQ); -template<class Impl> -void -SimpleRename<Impl>::tick() -{ - // Rename will need to try to rename as many instructions as it - // has bandwidth, unless it is blocked. - - // Check if _status is BarrierStall. If so, then check if the number - // of free ROB entries is equal to the number of total ROB entries. - // Once equal then wake this stage up. Set status to unblocking maybe. - - if (_status != Blocked && _status != Squashing) { - DPRINTF(Rename, "Rename: Status is not blocked, will attempt to " - "run stage.\n"); - // Make sure that the skid buffer has something in it if the - // status is unblocking. - assert(_status == Unblocking ? !skidBuffer.empty() : 1); - - rename(); - - // If the status was unblocking, then instructions from the skid - // buffer were used. Remove those instructions and handle - // the rest of unblocking. - if (_status == Unblocking) { - ++renameUnblockCycles; - - if (fromDecode->size > 0) { - // Add the current inputs onto the skid buffer, so they can be - // reprocessed when this stage unblocks. - skidBuffer.push(*fromDecode); - } + //DPRINTF(Rename,"[tid:%i]: %i lsq free\n",tid,num_free); - unblock(); - } - } else if (_status == Blocked) { - ++renameBlockCycles; + return num_free; +} - // If stage is blocked and still receiving valid instructions, - // make sure to store them in the skid buffer. - if (fromDecode->size > 0) { +template <class Impl> +unsigned +DefaultRename<Impl>::validInsts() +{ + unsigned inst_count = 0; - block(); + for (int i=0; i<fromDecode->size; i++) { + if (!fromDecode->insts[i]->squashed) + inst_count++; + } - // Continue to tell previous stage to stall. - toDecode->renameInfo.stall = true; - } + return inst_count; +} - if (!fromIEW->iewInfo.stall && - !fromCommit->commitInfo.stall && - calcFreeROBEntries() > 0 && - calcFreeIQEntries() > 0 && - renameMap->numFreeEntries() > 0) { - - // Need to be sure to check all blocking conditions above. - // If they have cleared, then start unblocking. - DPRINTF(Rename, "Rename: Stall signals cleared, going to " - "unblock.\n"); - _status = Unblocking; - - // Continue to tell previous stage to block until this stage - // is done unblocking. - toDecode->renameInfo.stall = true; - } else { - // Otherwise no conditions have changed. Tell previous - // stage to continue blocking. - toDecode->renameInfo.stall = true; - } +template <class Impl> +void +DefaultRename<Impl>::readStallSignals(unsigned tid) +{ + if (fromIEW->iewBlock[tid]) { + stalls[tid].iew = true; + } - if (fromCommit->commitInfo.squash || - fromCommit->commitInfo.robSquashing) { - squash(); - return; - } - } else if (_status == Squashing) { - ++renameSquashCycles; + if (fromIEW->iewUnblock[tid]) { + assert(stalls[tid].iew); + stalls[tid].iew = false; + } - if (fromCommit->commitInfo.squash) { - squash(); - } else if (!fromCommit->commitInfo.squash && - !fromCommit->commitInfo.robSquashing) { + if (fromCommit->commitBlock[tid]) { + stalls[tid].commit = true; + } - DPRINTF(Rename, "Rename: Done squashing, going to running.\n"); - _status = Running; - rename(); - } else { - doSquash(); - } + if (fromCommit->commitUnblock[tid]) { + assert(stalls[tid].commit); + stalls[tid].commit = false; } +} - // Ugly code, revamp all of the tick() functions eventually. - if (fromCommit->commitInfo.doneSeqNum != 0 && _status != Squashing) { -#if !FULL_SYSTEM - if (!fromCommit->commitInfo.squash) { - removeFromHistory(fromCommit->commitInfo.doneSeqNum); - } -#else - removeFromHistory(fromCommit->commitInfo.doneSeqNum); -#endif +template <class Impl> +bool +DefaultRename<Impl>::checkStall(unsigned 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 (stalls[tid].commit) { + DPRINTF(Rename,"[tid:%i]: Stall from Commit 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 (calcFreeLSQEntries(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> +template <class Impl> void -SimpleRename<Impl>::rename() -{ - // Check if any of the stages ahead of rename are telling rename - // to squash. The squash() function will also take care of fixing up - // the rename map and the free list. - if (fromCommit->commitInfo.squash || - fromCommit->commitInfo.robSquashing) { - DPRINTF(Rename, "Rename: Receiving signal from Commit to squash.\n"); - squash(); - return; +DefaultRename<Impl>::readFreeEntries(unsigned tid) +{ + bool updated = false; + if (fromIEW->iewInfo[tid].usedIQ) { + freeEntries[tid].iqEntries = + fromIEW->iewInfo[tid].freeIQEntries; + updated = true; } - // Check if time buffer is telling this stage to stall. - if (fromIEW->iewInfo.stall || - fromCommit->commitInfo.stall) { - DPRINTF(Rename, "Rename: Receiving signal from IEW/Commit to " - "stall.\n"); - block(); - return; + if (fromIEW->iewInfo[tid].usedLSQ) { + freeEntries[tid].lsqEntries = + fromIEW->iewInfo[tid].freeLSQEntries; + updated = true; } - // Check if the current status is squashing. If so, set its status - // to running and resume execution the next cycle. - if (_status == Squashing) { - DPRINTF(Rename, "Rename: Done squashing.\n"); - _status = Running; - return; + if (fromCommit->commitInfo[tid].usedROB) { + freeEntries[tid].robEntries = + fromCommit->commitInfo[tid].freeROBEntries; + emptyROB[tid] = fromCommit->commitInfo[tid].emptyROB; + updated = true; } - // Check the decode queue to see if instructions are available. - // If there are no available instructions to rename, then do nothing. - // Or, if the stage is currently unblocking, then go ahead and run it. - if (fromDecode->size == 0 && _status != Unblocking) { - DPRINTF(Rename, "Rename: Nothing to do, breaking out early.\n"); - // Should I change status to idle? - return; - } - - //////////////////////////////////// - // Actual rename part. - //////////////////////////////////// - - DynInstPtr inst; + DPRINTF(Rename, "[tid:%i]: Free IQ: %i, Free ROB: %i, Free LSQ: %i\n", + tid, + freeEntries[tid].iqEntries, + freeEntries[tid].robEntries, + freeEntries[tid].lsqEntries); - // If we're unblocking, then we may be in the middle of an instruction - // group. Subtract off numInst to get the proper number of instructions - // left. - int insts_available = _status == Unblocking ? - skidBuffer.front().size - numInst : - fromDecode->size; + DPRINTF(Rename, "[tid:%i]: %i instructions not yet in ROB\n", + tid, instsInProgress[tid]); +} - bool block_this_cycle = false; +template <class Impl> +bool +DefaultRename<Impl>::checkSignalsAndUpdate(unsigned tid) +{ + // Check if there's a squash signal, squash if there is + // Check stall signals, block if necessary. + // If status was blocked + // check if stall conditions have passed + // if so then go to unblocking + // If status was Squashing + // check if squashing is not high. Switch to running this cycle. + // 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(tid); + + return true; + } - // Will have to do a different calculation for the number of free - // entries. Number of free entries recorded on this cycle - - // renameWidth * renameToDecodeDelay - int free_rob_entries = calcFreeROBEntries(); - int free_iq_entries = calcFreeIQEntries(); - int min_iq_rob = min(free_rob_entries, free_iq_entries); + if (fromCommit->commitInfo[tid].robSquashing) { + DPRINTF(Rename, "[tid:%u]: ROB is still squashing.\n", tid); - unsigned to_iew_index = 0; + renameStatus[tid] = Squashing; - // Check if there's any space left. - if (min_iq_rob <= 0) { - DPRINTF(Rename, "Rename: Blocking due to no free ROB or IQ " - "entries.\n" - "Rename: ROB has %d free entries.\n" - "Rename: IQ has %d free entries.\n", - free_rob_entries, - free_iq_entries); - block(); - // Tell previous stage to stall. - toDecode->renameInfo.stall = true; + return true; + } - if (free_rob_entries <= 0) { - ++renameROBFullEvents; - } else { - ++renameIQFullEvents; - } + if (checkStall(tid)) { + return block(tid); + } - return; - } else if (min_iq_rob < insts_available) { - DPRINTF(Rename, "Rename: Will have to block this cycle. Only " - "%i insts can be renamed due to IQ/ROB limits.\n", - min_iq_rob); + if (renameStatus[tid] == Blocked) { + DPRINTF(Rename, "[tid:%u]: Done blocking, switching to unblocking.\n", + tid); - insts_available = min_iq_rob; + renameStatus[tid] = Unblocking; - block_this_cycle = true; + unblock(tid); - if (free_rob_entries < free_iq_entries) { - ++renameROBFullEvents; - } else { - ++renameIQFullEvents; - } + return true; } - while (insts_available > 0) { - DPRINTF(Rename, "Rename: Sending instructions to iew.\n"); + if (renameStatus[tid] == Squashing) { + // Switch status to running if rename isn't being told to block or + // squash this cycle. + DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", + tid); - // Get the next instruction either from the skid buffer or the - // decode queue. - inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : - fromDecode->insts[numInst]; + renameStatus[tid] = Running; - if (inst->isSquashed()) { - DPRINTF(Rename, "Rename: instruction %i with PC %#x is " - "squashed, skipping.\n", - inst->seqNum, inst->readPC()); + return false; + } - // Go to the next instruction. - ++numInst; + if (renameStatus[tid] == SerializeStall) { + // Stall ends once the ROB is free. + DPRINTF(Rename, "[tid:%u]: Done with serialize stall, switching to " + "unblocking.\n", tid); - ++renameSquashedInsts; + DynInstPtr serial_inst = serializeInst[tid]; - // Decrement how many instructions are available. - --insts_available; + renameStatus[tid] = Unblocking; - continue; - } + unblock(tid); - DPRINTF(Rename, "Rename: Processing instruction %i with PC %#x.\n", - inst->seqNum, inst->readPC()); - - // If it's a trap instruction, then it needs to wait here within - // rename until the ROB is empty. Needs a way to detect that the - // ROB is empty. Maybe an event? - // Would be nice if it could be avoided putting this into a - // specific stage and instead just put it into the AlphaFullCPU. - // Might not really be feasible though... - // (EXCB, TRAPB) - if (inst->isSerializing()) { - panic("Rename: Serializing instruction encountered.\n"); - DPRINTF(Rename, "Rename: Serializing instruction " - "encountered.\n"); - - // Change status over to BarrierStall so that other stages know - // what this is blocked on. - _status = BarrierStall; + DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with " + "PC %#x.\n", + tid, serial_inst->seqNum, serial_inst->readPC()); - block_this_cycle = true; + // Put instruction into queue here. + serial_inst->clearSerializeBefore(); - break; + if (!skidBuffer[tid].empty()) { + skidBuffer[tid].push_front(serial_inst); + } else { + insts[tid].push_front(serial_inst); } - // Check here to make sure there are enough destination registers - // to rename to. Otherwise block. - if (renameMap->numFreeEntries() < inst->numDestRegs()) - { - DPRINTF(Rename, "Rename: Blocking due to lack of free " - "physical registers to rename to.\n"); - // Need some sort of event based on a register being freed. - - block_this_cycle = true; + DPRINTF(Rename, "[tid:%u]: Instruction must be processed by rename." + " Adding to front of list.", tid); - ++renameFullRegistersEvents; + serializeInst[tid] = NULL; - break; - } + return true; + } - renameSrcRegs(inst); + // 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; +} - renameDestRegs(inst); +template<class Impl> +void +DefaultRename<Impl>::serializeAfter(InstQueue &inst_list, + unsigned tid) +{ + if (inst_list.empty()) { + // Mark a bit to say that I must serialize on the next instruction. + serializeOnNextInst[tid] = true; + return; + } - // Put instruction in rename queue. - toIEW->insts[to_iew_index] = inst; - ++(toIEW->size); + // Set the next instruction as serializing. + inst_list.front()->setSerializeBefore(); +} - // Decrease the number of free ROB and IQ entries. - --free_rob_entries; - --free_iq_entries; +template <class Impl> +inline void +DefaultRename<Impl>::incrFullStat(const FullSource &source) +{ + switch (source) { + case ROB: + ++renameROBFullEvents; + break; + case IQ: + ++renameIQFullEvents; + break; + case LSQ: + ++renameLSQFullEvents; + break; + default: + panic("Rename full stall stat should be incremented for a reason!"); + break; + } +} - // Increment which instruction we're on. - ++to_iew_index; - ++numInst; +template <class Impl> +void +DefaultRename<Impl>::dumpHistory() +{ + typename list<RenameHistory>::iterator buf_it; - ++renameRenamedInsts; + for (int i = 0; i < numThreads; i++) { - // Decrement how many instructions are available. - --insts_available; - } + buf_it = historyBuffer[i].begin(); - // Check if there's any instructions left that haven't yet been renamed. - // If so then block. - if (block_this_cycle) { - block(); + while (buf_it != historyBuffer[i].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); - toDecode->renameInfo.stall = true; - } else { - // If we had a successful rename and didn't have to exit early, then - // reset numInst so it will refer to the correct instruction on next - // run. - numInst = 0; + buf_it++; + } } } |