summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/first_stage.cc
diff options
context:
space:
mode:
authorKorey Sewell <ksewell@umich.edu>2009-02-10 15:49:29 -0800
committerKorey Sewell <ksewell@umich.edu>2009-02-10 15:49:29 -0800
commit973d8b8b13b8e4ea178cafa95aaf6538699b8b15 (patch)
tree79321a7384b1fbd183a39e98e28dfa4e9e99d828 /src/cpu/inorder/first_stage.cc
parent36d9065f5f716f88c82a3f4e9a75fa040039aa0a (diff)
downloadgem5-973d8b8b13b8e4ea178cafa95aaf6538699b8b15.tar.xz
InOrder: Import new inorder CPU model from MIPS.
This model currently only works in MIPS_SE mode, so it will take some effort to clean it up and make it generally useful. Hopefully people are willing to help make that happen!
Diffstat (limited to 'src/cpu/inorder/first_stage.cc')
-rw-r--r--src/cpu/inorder/first_stage.cc251
1 files changed, 251 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..ce30f8466
--- /dev/null
+++ b/src/cpu/inorder/first_stage.cc
@@ -0,0 +1,251 @@
+/*
+ * 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)
+{
+ for(int tid=0; tid < this->numThreads; tid++) {
+ stageStatus[tid] = Running;
+ }
+
+ numFetchingThreads = 1;
+
+ fetchPolicy = RoundRobin;
+}
+
+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 && canSendInstToNextStage(); 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;
+}