summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/pipeline_stage.cc
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2015-04-20 12:46:35 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2015-04-20 12:46:35 -0400
commitcd76e34056afab83697beef1d1ced94ee671a20d (patch)
tree8adaa80ba72593bdf67103ad5cd0a072b95e8acb /src/cpu/inorder/pipeline_stage.cc
parent076ea249ae47b935bea424954174f33fdecb7fcc (diff)
downloadgem5-cd76e34056afab83697beef1d1ced94ee671a20d.tar.xz
cpu: Remove the InOrderCPU from the tree
This patch takes the final step in removing the InOrderCPU from the tree. Rest in peace. The MinorCPU is now used to model an in-order microarchitecture, and long term the MinorCPU will eventually be renamed InOrderCPU.
Diffstat (limited to 'src/cpu/inorder/pipeline_stage.cc')
-rw-r--r--src/cpu/inorder/pipeline_stage.cc1125
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++;
- }
- }
-
-}