diff options
Diffstat (limited to 'src/cpu/inorder/pipeline_stage.cc')
-rw-r--r-- | src/cpu/inorder/pipeline_stage.cc | 1125 |
1 files changed, 0 insertions, 1125 deletions
diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc deleted file mode 100644 index 5e94c665f..000000000 --- a/src/cpu/inorder/pipeline_stage.cc +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * 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: Korey Sewell - * - */ - -#include "base/str.hh" -#include "config/the_isa.hh" -#include "cpu/inorder/cpu.hh" -#include "cpu/inorder/pipeline_stage.hh" -#include "cpu/inorder/resource_pool.hh" -#include "debug/Activity.hh" -#include "debug/InOrderStage.hh" -#include "debug/InOrderStall.hh" -#include "debug/Resource.hh" -#include "debug/ThreadModel.hh" - -using namespace std; -using namespace ThePipeline; - -PipelineStage::PipelineStage(Params *params, unsigned stage_num) - : stageNum(stage_num), stageWidth(params->stageWidth), - numThreads(ThePipeline::MaxThreads), _status(Inactive), - stageBufferMax(params->stageWidth), - prevStageValid(false), nextStageValid(false), idle(false) -{ - init(params); -} - -PipelineStage::~PipelineStage() -{ - for(ThreadID tid = 0; tid < numThreads; tid++) { - skidBuffer[tid].clear(); - stalls[tid].resources.clear(); - } -} - -void -PipelineStage::init(Params *params) -{ - for(ThreadID tid = 0; tid < numThreads; tid++) { - stageStatus[tid] = Idle; - - for (int stNum = 0; stNum < NumStages; stNum++) { - stalls[tid].stage[stNum] = false; - } - stalls[tid].resources.clear(); - - if (stageNum < BackEndStartStage) - lastStallingStage[tid] = BackEndStartStage - 1; - else - lastStallingStage[tid] = NumStages - 1; - } - - if ((InOrderCPU::ThreadModel) params->threadModel == - InOrderCPU::SwitchOnCacheMiss) { - switchedOutBuffer.resize(ThePipeline::MaxThreads); - switchedOutValid.resize(ThePipeline::MaxThreads); - } -} - - -std::string -PipelineStage::name() const -{ - return cpu->name() + ".stage" + to_string(stageNum); -} - - -void -PipelineStage::regStats() -{ - idleCycles - .name(name() + ".idleCycles") - .desc("Number of cycles 0 instructions are processed."); - - runCycles - .name(name() + ".runCycles") - .desc("Number of cycles 1+ instructions are processed."); - - utilization - .name(name() + ".utilization") - .desc("Percentage of cycles stage was utilized (processing insts).") - .precision(6); - utilization = (runCycles / cpu->numCycles) * 100; - -} - - -void -PipelineStage::setCPU(InOrderCPU *cpu_ptr) -{ - cpu = cpu_ptr; - - DPRINTF(InOrderStage, "Set CPU pointer.\n"); - - tracer = dynamic_cast<Trace::InOrderTrace *>(cpu->getTracer()); -} - - -void -PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(InOrderStage, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to write information back to fetch. - // @todo: should this be writing to the next stage => -1 and reading from is (0)??? - toPrevStages = timeBuffer->getWire(0); - - // Create wires to get information from proper places in time buffer. - fromNextStages = timeBuffer->getWire(-1); -} - - -void -PipelineStage::setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr) -{ - DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n"); - prevStageQueue = prev_stage_ptr; - - // Setup wire to read information from fetch queue. - prevStage = prevStageQueue->getWire(-1); - - prevStageValid = true; -} - - - -void -PipelineStage::setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr) -{ - DPRINTF(InOrderStage, "Setting next stage pointer.\n"); - nextStageQueue = next_stage_ptr; - - // Setup wire to write information to proper place in stage queue. - nextStage = nextStageQueue->getWire(0); - nextStageValid = true; -} - - - -void -PipelineStage::setActiveThreads(list<ThreadID> *at_ptr) -{ - DPRINTF(InOrderStage, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -/*inline void -PipelineStage::switchToActive() -{ - if (_status == Inactive) { - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(stageNum); - - _status = Active; - } -}*/ - -void -PipelineStage::switchOut() -{ - // Stage can immediately switch out. - panic("Switching Out of Stages Unimplemented"); -} - - -void -PipelineStage::takeOverFrom() -{ - _status = Inactive; - - // Be sure to reset state and clear out any old instructions. - for (ThreadID tid = 0; tid < numThreads; ++tid) { - stageStatus[tid] = Idle; - - for (int stNum = 0; stNum < NumStages; stNum++) { - stalls[tid].stage[stNum] = false; - } - - stalls[tid].resources.clear(); - - skidBuffer[tid].clear(); - } - wroteToTimeBuffer = false; -} - - - -bool -PipelineStage::checkStall(ThreadID tid) const -{ - bool ret_val = false; - - // Only check pipeline stall from stage directly following this stage - if (nextStageValid && stalls[tid].stage[stageNum + 1]) { - DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n", - tid, stageNum + 1); - ret_val = true; - } - - if (!stalls[tid].resources.empty()) { -#if TRACING_ON - string stall_src; - - for (int i=0; i < stalls[tid].resources.size(); i++) { - stall_src += stalls[tid].resources[i]->res->name() + ":"; - } - - DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n", - tid, stall_src); -#endif - ret_val = true; - } - - return ret_val; -} - - -void -PipelineStage::removeStalls(ThreadID tid) -{ - for (int st_num = 0; st_num < NumStages; st_num++) { - if (stalls[tid].stage[st_num]) { - DPRINTF(InOrderStage, "Removing stall from stage %i.\n", - st_num); - stalls[tid].stage[st_num] = false; - } - - if (toPrevStages->stageBlock[st_num][tid]) { - DPRINTF(InOrderStage, "Removing pending block from stage %i.\n", - st_num); - toPrevStages->stageBlock[st_num][tid] = false; - } - - if (fromNextStages->stageBlock[st_num][tid]) { - DPRINTF(InOrderStage, "Removing pending block from stage %i.\n", - st_num); - fromNextStages->stageBlock[st_num][tid] = false; - } - } - stalls[tid].resources.clear(); -} - -inline bool -PipelineStage::prevStageInstsValid() -{ - return prevStage->insts.size() > 0; -} - -bool -PipelineStage::isBlocked(ThreadID tid) -{ - return stageStatus[tid] == Blocked; -} - -bool -PipelineStage::block(ThreadID tid) -{ - DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to " - "previous stages.\n", tid); - - // If the stage status is blocked or unblocking then stage has not yet - // signalled fetch to unblock. In that case, there is no need to tell - // fetch to block. - if (stageStatus[tid] != Blocked) { - if (stageStatus[tid] != Unblocking) { - wroteToTimeBuffer = true; - } - - stageStatus[tid] = Blocked; - - if (prevStageValid) { - DPRINTF(InOrderStage, "[tid:%d]: Stage %i setting block signal.\n", - tid, stageNum); - toPrevStages->stageBlock[stageNum][tid] = true; - } - - return true; - } - - - return false; -} - -void -PipelineStage::blockDueToBuffer(ThreadID tid) -{ - DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to " - "next stage.\n", tid); - - if (stageStatus[tid] != Blocked) { - if (stageStatus[tid] != Unblocking) { - wroteToTimeBuffer = true; - } - - // Set the status to Blocked. - stageStatus[tid] = Blocked; - } -} - -bool -PipelineStage::unblock(ThreadID tid) -{ - // @todo: Shouldnt this be if any available slots are open??? - // Stage is done unblocking only if the skid buffer is empty. - if (skidBuffer[tid].empty()) { - DPRINTF(InOrderStage, "[tid:%u]: Done unblocking.\n", tid); - - if (prevStageValid) - toPrevStages->stageUnblock[stageNum][tid] = true; - - wroteToTimeBuffer = true; - - stageStatus[tid] = Running; - - return true; - } - - DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid); - return false; -} - -void -PipelineStage::setupSquash(DynInstPtr inst, ThreadID tid) -{ - if (cpu->lastSquashCycle[tid] == curTick() && - cpu->squashSeqNum[tid] < inst->seqNum){ - DPRINTF(Resource, "Ignoring [sn:%i] branch squash signal due to " - "another stage's squash signal for after [sn:%i].\n", - inst->seqNum, cpu->squashSeqNum[tid]); - } else { - InstSeqNum squash_seq_num = inst->squashSeqNum; - unsigned squash_stage = (nextStageValid) ? stageNum + 1 - : stageNum; - - toPrevStages->stageInfo[squash_stage][tid].squash = true; - toPrevStages->stageInfo[squash_stage][tid].doneSeqNum = - squash_seq_num; - - DPRINTF(InOrderStage, "[tid:%i]: Setting up squashing after " - "[sn:%i], due to [sn:%i] %s. Squash-Start-Stage:%i\n", - tid, squash_seq_num, inst->seqNum, inst->instName(), - squash_stage); - - // Save squash num for later stage use - cpu->lastSquashCycle[tid] = curTick(); - cpu->squashSeqNum[tid] = squash_seq_num; - } -} - -void -PipelineStage::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid) -{ - squash(seq_num, tid); -} - -void -PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid) -{ - DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from " - "incoming stage queue.\n", tid); - - int insts_from_prev_stage = prevStage->insts.size(); - for (int i=0; i < insts_from_prev_stage; i++) { - if (prevStage->insts[i]->threadNumber == tid && - prevStage->insts[i]->seqNum > squash_seq_num) { - DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, " - "[sn:%i] PC %s.\n", - tid, - prevStage->insts[i]->seqNum, - prevStage->insts[i]->pcState()); - prevStage->insts[i]->setSquashed(); - - prevStage->insts[i] = cpu->dummyBufferInst; - } - } -} - -void -PipelineStage::squash(InstSeqNum squash_seq_num, ThreadID tid) -{ - // Set status to squashing. - stageStatus[tid] = Squashing; - - squashPrevStageInsts(squash_seq_num, tid); - - DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage" - " skidbuffer.\n", tid); - //@TODO: Walk Through List Using iterator and remove - // all instructions over the value - std::list<DynInstPtr>::iterator cur_it = skidBuffer[tid].begin(); - std::list<DynInstPtr>::iterator end_it = skidBuffer[tid].end(); - - while (cur_it != end_it) { - if ((*cur_it)->seqNum <= squash_seq_num) { - DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer " - "instructions (starting w/[sn:%i]) before " - "[sn:%i]. %i insts left.\n", tid, - (*cur_it)->seqNum, squash_seq_num, - skidBuffer[tid].size()); - cur_it++; - } else { - DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] " - " PC %s.\n", tid, (*cur_it)->seqNum, (*cur_it)->pc); - (*cur_it)->setSquashed(); - cur_it = skidBuffer[tid].erase(cur_it); - } - - } - -} - -int -PipelineStage::stageBufferAvail() -{ - unsigned total = 0; - - for (int i=0; i < ThePipeline::MaxThreads; i++) { - total += skidBuffer[i].size(); - } - - int avail = stageBufferMax - total; - assert(avail >= 0); - - return avail; -} - -bool -PipelineStage::canSendInstToStage(unsigned stage_num) -{ - bool buffer_avail = false; - - if (cpu->pipelineStage[stage_num]->prevStageValid) { - buffer_avail = cpu->pipelineStage[stage_num]->stageBufferAvail() - - cpu->pipelineStage[stage_num-1]->nextStage->insts.size() >= 1; - } - - if (!buffer_avail && nextStageQueueValid(stage_num)) { - DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", - stageNum + 1); - } - - return buffer_avail; -} - -int -PipelineStage::skidSize() -{ - int total = 0; - - for (int i=0; i < ThePipeline::MaxThreads; i++) { - total += skidBuffer[i].size(); - } - - return total; -} - -bool -PipelineStage::skidsEmpty() -{ - list<ThreadID>::iterator threads = activeThreads->begin(); - - while (threads != activeThreads->end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - - - -void -PipelineStage::updateStatus() -{ - bool any_unblocking = false; - - list<ThreadID>::iterator threads = activeThreads->begin(); - - while (threads != activeThreads->end()) { - ThreadID tid = *threads++; - - if (stageStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // Stage will have activity if it's unblocking. - if (any_unblocking) { - if (_status == Inactive) { - _status = Active; - - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(stageNum); - } - } else { - // If it's not unblocking, then stage will not have any internal - // activity. Switch it to inactive. - if (_status == Active) { - _status = Inactive; - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(stageNum); - } - } -} - -void -PipelineStage::activateThread(ThreadID tid) -{ - if (cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) { - if (!switchedOutValid[tid]) { - DPRINTF(InOrderStage, "[tid:%i] No instruction available in " - "switch out buffer.\n", tid); - } else { - DynInstPtr inst = switchedOutBuffer[tid]; - - DPRINTF(InOrderStage,"[tid:%i]: Re-Inserting [sn:%lli] PC:%s into" - " stage skidBuffer %i\n", tid, inst->seqNum, - inst->pcState(), inst->threadNumber); - - // Make instruction available for pipeline processing - skidBuffer[tid].push_back(inst); - - // Update PC so that we start fetching after this instruction to - // prevent "double"-execution of instructions - cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType) - ResourcePool::UpdateAfterContextSwitch, - inst, Cycles(0), 0, tid); - - // Clear switchout buffer - switchedOutBuffer[tid] = NULL; - switchedOutValid[tid] = false; - - // Update any CPU stats based off context switches - cpu->updateContextSwitchStats(); - } - } - -} - - -void -PipelineStage::sortInsts() -{ - if (prevStageValid) { - assert(prevStage->insts.size() <= stageWidth); - - int insts_from_prev_stage = prevStage->insts.size(); - int insts_from_cur_stage = skidSize(); - DPRINTF(InOrderStage, "%i insts available from stage buffer %i. Stage " - "currently has %i insts from last cycle.\n", - insts_from_prev_stage, prevStageQueue->id(), - insts_from_cur_stage); - - int inserted_insts = 0; - - for (int i = 0; i < insts_from_prev_stage; i++) { - if (prevStage->insts[i]->isSquashed()) { - DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], " - "not inserting into stage buffer.\n", - prevStage->insts[i]->readTid(), - prevStage->insts[i]->seqNum); - continue; - } - - ThreadID tid = prevStage->insts[i]->threadNumber; - - if (inserted_insts + insts_from_cur_stage == stageWidth) { - DPRINTF(InOrderStage, "Stage %i has accepted all insts " - "possible for this tick. Placing [sn:%i] in stage %i skidBuffer\n", - stageNum, prevStage->insts[i]->seqNum, stageNum - 1); - cpu->pipelineStage[stageNum - 1]-> - skidBuffer[tid].push_front(prevStage->insts[i]); - - int prev_stage = stageNum - 1; - if (cpu->pipelineStage[prev_stage]->stageStatus[tid] == Running || - cpu->pipelineStage[prev_stage]->stageStatus[tid] == Idle) { - cpu->pipelineStage[prev_stage]->stageStatus[tid] = Unblocking; - } - } else { - DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage " - "buffer.\n", prevStage->insts[i]->readTid(), - prevStage->insts[i]->seqNum); - - skidBuffer[tid].push_back(prevStage->insts[i]); - } - - prevStage->insts[i] = cpu->dummyBufferInst; - - inserted_insts++; - } - } -} - - - -void -PipelineStage::readStallSignals(ThreadID tid) -{ - for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid]; - stage_idx++) { - - DPRINTF(InOrderStage, "[tid:%i] Reading stall signals from Stage " - "%i. Block:%i Unblock:%i.\n", - tid, - stage_idx, - fromNextStages->stageBlock[stage_idx][tid], - fromNextStages->stageUnblock[stage_idx][tid]); - - // Check for Stage Blocking Signal - if (fromNextStages->stageBlock[stage_idx][tid]) { - DPRINTF(InOrderStage, "[tid:%i] Stall from stage %i set.\n", tid, - stage_idx); - stalls[tid].stage[stage_idx] = true; - } - - // Check for Stage Unblocking Signal - if (fromNextStages->stageUnblock[stage_idx][tid]) { - DPRINTF(InOrderStage, "[tid:%i] Stall from stage %i unset.\n", tid, - stage_idx); - stalls[tid].stage[stage_idx] = false; - } - } -} - - - -bool -PipelineStage::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. - - // Update the per thread stall statuses. - readStallSignals(tid); - - // Check for squash from later pipeline stages - for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) { - if (fromNextStages->stageInfo[stage_idx][tid].squash) { - DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to " - "squash from stage %u.\n", tid, stage_idx); - InstSeqNum squash_seq_num = fromNextStages-> - stageInfo[stage_idx][tid].doneSeqNum; - squash(squash_seq_num, tid); - break; //return true; - } - } - - if (checkStall(tid)) { - return block(tid); - } - - if (stageStatus[tid] == Blocked) { - DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to " - "unblocking.\n", tid); - - stageStatus[tid] = Unblocking; - - unblock(tid); - - return true; - } - - if (stageStatus[tid] == Squashing) { - if (!skidBuffer[tid].empty()) { - DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to " - "unblocking.\n", tid); - - stageStatus[tid] = Unblocking; - } else { - // Switch status to running if stage isn't being told to block or - // squash this cycle. - DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to " - "running.\n", tid); - - stageStatus[tid] = Running; - } - - return true; - } - - // If we've reached this point, we have not gotten any signals that - // cause stage to change its status. Stage remains the same as before.*/ - return false; -} - - - -void -PipelineStage::tick() -{ - idle = false; - - wroteToTimeBuffer = false; - - bool status_change = false; - - sortInsts(); - - instsProcessed = 0; - - processStage(status_change); - - if (status_change) { - updateStatus(); - } - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); - } - - DPRINTF(InOrderStage, "\n\n"); -} - -void -PipelineStage::setResStall(ResReqPtr res_req, ThreadID tid) -{ - DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name()); - stalls[tid].resources.push_back(res_req); -} - -void -PipelineStage::unsetResStall(ResReqPtr res_req, ThreadID tid) -{ - // Search through stalls to find stalling request and then - // remove it - vector<ResReqPtr>::iterator req_it = stalls[tid].resources.begin(); - vector<ResReqPtr>::iterator req_end = stalls[tid].resources.end(); - - while (req_it != req_end) { - if( (*req_it)->res == res_req->res && // Same Resource - (*req_it)->inst == res_req->inst && // Same Instruction - (*req_it)->getSlot() == res_req->getSlot()) { - DPRINTF(InOrderStage, "[tid:%u]: Clearing stall by %s.\n", - tid, res_req->res->name()); - stalls[tid].resources.erase(req_it); - break; - } - - req_it++; - } - - if (stalls[tid].resources.size() == 0) { - DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource" - "stalls.\n", tid); - } -} - -// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be -// handled one at a time, but instead first come first serve by instruction? -// Questions are how should a pipeline stage handle thread-specific stalls & -// pipeline squashes -void -PipelineStage::processStage(bool &status_change) -{ - list<ThreadID>::iterator threads = activeThreads->begin(); - - //Check stall and squash signals. - while (threads != activeThreads->end()) { - ThreadID tid = *threads++; - - DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid); - status_change = checkSignalsAndUpdate(tid) || status_change; - - processThread(status_change, tid); - } - - if (nextStageValid) { - DPRINTF(InOrderStage, "%i insts now available for stage %i.\n", - nextStage->insts.size(), stageNum + 1); - } - - if (instsProcessed > 0) { - ++runCycles; - idle = false; - } else { - ++idleCycles; - idle = true; - } - - DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(), - stageNum); - - DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", - stageBufferAvail(), stageNum); -} - -void -PipelineStage::processThread(bool &status_change, ThreadID tid) -{ - // If status is Running or idle, - // call processInsts() - // If status is Unblocking, - // buffer any instructions coming from fetch - // continue trying to empty skid buffer - // check if stall conditions have passed - - // Stage should try to process as many instructions as its bandwidth - // will allow, as long as it is not currently blocked. - if (stageStatus[tid] == Running || - stageStatus[tid] == Idle) { - DPRINTF(InOrderStage, "[tid:%u]: Not blocked, so attempting to run " - "stage.\n",tid); - - processInsts(tid); - } else if (stageStatus[tid] == Unblocking) { - // Make sure that the skid buffer has something in it if the - // status is unblocking. - assert(!skidsEmpty()); - - // If the status was unblocking, then instructions from the skid - // buffer were used. Remove those instructions and handle - // the rest of unblocking. - processInsts(tid); - - status_change = unblock(tid) || status_change; - } -} - - -void -PipelineStage::processInsts(ThreadID tid) -{ - // Instructions can come either from the skid buffer or the list of - // instructions coming from fetch, depending on stage's status. - int insts_available = skidBuffer[tid].size(); - - std::list<DynInstPtr> &insts_to_stage = skidBuffer[tid]; - - if (insts_available == 0) { - DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out" - " early.\n",tid); - return; - } - - DynInstPtr inst; - bool last_req_completed = true; - - while (insts_available > 0 && - instsProcessed < stageWidth && - last_req_completed) { - assert(!insts_to_stage.empty()); - - inst = insts_to_stage.front(); - - DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] " - "%s with PC %s\n", tid, inst->seqNum, - inst->instName(), - inst->pcState()); - - if (inst->isSquashed()) { - DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %s is " - "squashed, skipping.\n", - tid, inst->seqNum, inst->pcState()); - - insts_to_stage.pop_front(); - - --insts_available; - - continue; - } - - int reqs_processed = 0; - last_req_completed = processInstSchedule(inst, reqs_processed); - - // If the instruction isnt squashed & we've completed one request - // Then we can officially count this instruction toward the stage's - // bandwidth count - if (reqs_processed > 0) - instsProcessed++; - - // Don't let instruction pass to next stage if it hasnt completed - // all of it's requests for this stage. - if (!last_req_completed) - continue; - - // Send to Next Stage or Break Loop - if (nextStageValid && !sendInstToNextStage(inst)) { - DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage" - " %i.\n", tid, inst->seqNum,inst->nextStage); - break; - } - - insts_to_stage.pop_front(); - - --insts_available; - } - - // If we didn't process all instructions, then we will need to block - // and put all those instructions into the skid buffer. - if (!insts_to_stage.empty()) { - blockDueToBuffer(tid); - } - - // Record that stage has written to the time buffer for activity - // tracking. - if (instsProcessed) { - wroteToTimeBuffer = true; - } -} - -bool -PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed) -{ - bool last_req_completed = true; - ThreadID tid = inst->readTid(); - - if (inst->nextResStage() == stageNum) { - int res_stage_num = inst->nextResStage(); - - while (res_stage_num == stageNum) { - int res_num = inst->nextResource(); - - - DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s." - "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); - - ResReqPtr req = cpu->resPool->request(res_num, inst); - assert(req->valid); - - bool req_completed = req->isCompleted(); - bool done_in_pipeline = false; - if (req_completed) { - DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s " - "completed.\n", tid, inst->seqNum, - cpu->resPool->name(res_num)); - - reqs_processed++; - - req->stagePasses++; - - done_in_pipeline = inst->finishSkedEntry(); - if (done_in_pipeline) { - DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] finished " - "in pipeline.\n", tid, inst->seqNum); - } - } else { - DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed." - "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); - - last_req_completed = false; - - if (req->isMemStall() && - cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) { - // Save Stalling Instruction - DPRINTF(ThreadModel, "[tid:%i] [sn:%i] Detected cache " - "miss.\n", tid, inst->seqNum); - - DPRINTF(InOrderStage, "Inserting [tid:%i][sn:%i] into " - "switch out buffer.\n", tid, inst->seqNum); - - switchedOutBuffer[tid] = inst; - switchedOutValid[tid] = true; - - // Remove Thread From Pipeline & Resource Pool - inst->squashingStage = stageNum; - inst->squashSeqNum = inst->seqNum; - cpu->squashFromMemStall(inst, tid); - - // Switch On Cache Miss - //===================== - // Suspend Thread at end of cycle - DPRINTF(ThreadModel, "Suspending [tid:%i] due to cache " - "miss.\n", tid); - cpu->suspendContext(tid); - - // Activate Next Ready Thread at end of cycle - DPRINTF(ThreadModel, "Attempting to activate next ready " - "thread due to cache miss.\n"); - cpu->activateNextReadyContext(); - } - } - - // If this request is no longer needs to take up bandwidth in the - // resource, go ahead and free that bandwidth up - if (req->doneInResource) { - req->freeSlot(); - } - - // No longer need to process this instruction if the last - // request it had wasn't completed or if there is nothing - // else for it to do in the pipeline - if (done_in_pipeline || !req_completed) { - break; - } - - res_stage_num = inst->nextResStage(); - } - } else { - DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %s " - " needed no resources in stage %i.\n", - tid, inst->seqNum, inst->pcState(), stageNum); - } - - return last_req_completed; -} - -bool -PipelineStage::nextStageQueueValid(int stage_num) -{ - return cpu->pipelineStage[stage_num]->nextStageValid; -} - - -bool -PipelineStage::sendInstToNextStage(DynInstPtr inst) -{ - // Update Next Stage Variable in Instruction - // NOTE: Some Resources will update this nextStage var. to - // for bypassing, so can't always assume nextStage=stageNum+1 - if (inst->nextStage == stageNum) - inst->nextStage++; - - bool success = false; - ThreadID tid = inst->readTid(); - int next_stage = inst->nextStage; - int prev_stage = next_stage - 1; - - assert(next_stage >= 1); - assert(prev_stage >= 0); - - DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to " - "stage %u.\n", tid, stageNum+1); - - if (!canSendInstToStage(inst->nextStage)) { - DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to " - "stage %u.\n", tid, stageNum+1); - return false; - } - - - if (nextStageQueueValid(inst->nextStage - 1)) { - if (inst->seqNum > cpu->squashSeqNum[tid] && - curTick() == cpu->lastSquashCycle[tid]) { - DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping " - "insertion into stage %i queue.\n", tid, inst->seqNum, - inst->nextStage); - } else { - if (nextStageValid) { - DPRINTF(InOrderStage, "[tid:%u] %i slots available in next " - "stage buffer.\n", tid, - cpu->pipelineStage[next_stage]->stageBufferAvail()); - } - - DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " - "index %i of stage buffer %i queue.\n", - tid, inst->seqNum, - cpu->pipelineStage[prev_stage]->nextStage->insts.size(), - cpu->pipelineStage[prev_stage]->nextStageQueue->id()); - - // Place instructions in inter-stage communication struct for next - // pipeline stage to read next cycle - cpu->pipelineStage[prev_stage]->nextStage->insts.push_back(inst); - - success = true; - - // Take note of trace data for this inst & stage - if (inst->traceData) { - //@todo: exec traces are broke. fix them - inst->traceData->setStageCycle(stageNum, curTick()); - } - - } - } - - return success; -} - -void -PipelineStage::dumpInsts() -{ - cprintf("Insts in Stage %i skidbuffers\n",stageNum); - - for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) { - std::list<DynInstPtr>::iterator cur_it = skidBuffer[tid].begin(); - std::list<DynInstPtr>::iterator end_it = skidBuffer[tid].end(); - - while (cur_it != end_it) { - DynInstPtr inst = (*cur_it); - - cprintf("Inst. PC:%s\n[tid:%i]\n[sn:%i]\n\n", - inst->pcState(), inst->threadNumber, inst->seqNum); - - cur_it++; - } - } - -} |