diff options
Diffstat (limited to 'src/cpu/inorder/first_stage.cc')
-rw-r--r-- | src/cpu/inorder/first_stage.cc | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc new file mode 100644 index 000000000..5e389b256 --- /dev/null +++ b/src/cpu/inorder/first_stage.cc @@ -0,0 +1,248 @@ +/* + * 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 "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderTrace.hh" + +using namespace std; +using namespace ThePipeline; + +FirstStage::FirstStage(Params *params, unsigned stage_num) + : PipelineStage(params, stage_num), numFetchingThreads(1), + fetchPolicy(FirstStage::RoundRobin) +{ + for(int tid=0; tid < this->numThreads; tid++) { + stageStatus[tid] = Running; + } +} + +void +FirstStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + fetchPriorityList = &cpu->fetchPriorityList; + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); +} + + +void +FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + //stageStatus[tid] = Squashing; + + // Clear the instruction list and skid buffer in case they have any + // insts in them. + DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n"); + while (!insts[tid].empty()) { + if (insts[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= " + "squashing seqNum %i.\n", + tid, + insts[tid].front()->seqNum, + squash_seq_num); + + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + insts[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, insts[tid].front()->seqNum, insts[tid].front()->PC); + insts[tid].pop(); + } + + // Now that squash has propagated to the first stage, + // Alert CPU to remove instructions from the CPU instruction list. + // @todo: Move this to the CPU object. + cpu->removeInstsUntil(squash_seq_num, tid); +} + +void +FirstStage::processStage(bool &status_change) +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + status_change = checkSignalsAndUpdate(tid) || status_change; + } + + for (int threadFetched = 0; threadFetched < numFetchingThreads; + threadFetched++) { + int tid = getFetchingThread(fetchPolicy); + + if (tid >= 0) { + DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid); + processThread(status_change, tid); + } else { + DPRINTF(InOrderStage, "No more threads to fetch from.\n"); + } + } +} + +//@TODO: Note in documentation, that when you make a pipeline stage change, then +//make sure you change the first stage too +void +FirstStage::processInsts(unsigned tid) +{ + bool all_reqs_completed = true; + + for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) { + DynInstPtr inst; + bool new_inst = false; + + if (!insts[tid].empty()) { + inst = insts[tid].front(); + } else { + // Get new instruction. + new_inst = true; + + inst = new InOrderDynInst(cpu, + cpu->thread[tid], + cpu->nextInstSeqNum(tid), + tid); + +#if TRACING_ON + inst->traceData = + tracer->getInstRecord(ThePipeline::NumStages, + cpu->stageTracing, + cpu->thread[tid]->getTC()); + +#endif // TRACING_ON + + DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Add instruction to the CPU's list of instructions. + inst->setInstListIt(cpu->addInst(inst)); + + DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Create Front-End Resource Schedule For Instruction + ThePipeline::createFrontEndSchedule(inst); + } + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + all_reqs_completed = processInstSchedule(inst); + + if (!all_reqs_completed) { + if (new_inst) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all " + "requests for this stage. Keep in stage inst. " + "list.\n", tid, inst->seqNum); + insts[tid].push(inst); + } + break; + } else if (!insts[tid].empty()){ + insts[tid].pop(); + } + + sendInstToNextStage(inst); + //++stageProcessedInsts; + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +int +FirstStage::getFetchingThread(FetchPriority &fetch_priority) +{ + if (numThreads > 1) { + switch (fetch_priority) { + + case SingleThread: + return 0; + + case RoundRobin: + return roundRobin(); + + default: + return -1; + } + } else { + int tid = *((*activeThreads).begin()); + + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + return tid; + } else { + return -1; + } + } + +} + +int +FirstStage::roundRobin() +{ + list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin(); + list<unsigned>::iterator end = (*fetchPriorityList).end(); + + int high_pri; + + while (pri_iter != end) { + high_pri = *pri_iter; + + assert(high_pri <= numThreads); + + if (stageStatus[high_pri] == Running || + stageStatus[high_pri] == Idle) { + + (*fetchPriorityList).erase(pri_iter); + (*fetchPriorityList).push_back(high_pri); + + return high_pri; + } + + pri_iter++; + } + + return -1; +} |