summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/resources
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/resources
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/resources')
-rw-r--r--src/cpu/inorder/resources/agen_unit.cc98
-rw-r--r--src/cpu/inorder/resources/agen_unit.hh64
-rw-r--r--src/cpu/inorder/resources/bpred_unit.cc426
-rw-r--r--src/cpu/inorder/resources/bpred_unit.hh258
-rw-r--r--src/cpu/inorder/resources/branch_predictor.cc149
-rw-r--r--src/cpu/inorder/resources/branch_predictor.hh87
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc609
-rw-r--r--src/cpu/inorder/resources/cache_unit.hh305
-rw-r--r--src/cpu/inorder/resources/decode_unit.cc92
-rw-r--r--src/cpu/inorder/resources/decode_unit.hh68
-rw-r--r--src/cpu/inorder/resources/execution_unit.cc182
-rw-r--r--src/cpu/inorder/resources/execution_unit.hh77
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.cc324
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.hh119
-rw-r--r--src/cpu/inorder/resources/graduation_unit.cc113
-rw-r--r--src/cpu/inorder/resources/graduation_unit.hh70
-rw-r--r--src/cpu/inorder/resources/inst_buffer.cc222
-rw-r--r--src/cpu/inorder/resources/inst_buffer.hh93
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.cc156
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.hh109
-rw-r--r--src/cpu/inorder/resources/mem_dep_unit.hh66
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.cc291
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.hh138
-rw-r--r--src/cpu/inorder/resources/resource_list.hh47
-rw-r--r--src/cpu/inorder/resources/tlb_unit.cc186
-rw-r--r--src/cpu/inorder/resources/tlb_unit.hh124
-rw-r--r--src/cpu/inorder/resources/use_def.cc326
-rw-r--r--src/cpu/inorder/resources/use_def.hh102
28 files changed, 4901 insertions, 0 deletions
diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc
new file mode 100644
index 000000000..8e3d25656
--- /dev/null
+++ b/src/cpu/inorder/resources/agen_unit.cc
@@ -0,0 +1,98 @@
+/*
+ * 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 "cpu/inorder/resources/agen_unit.hh"
+
+AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+AGENUnit::execute(int slot_num)
+{
+ ResourceRequest* agen_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid;
+ int seq_num = inst->seqNum;
+
+ tid = inst->readTid();
+ agen_req->fault = NoFault;
+
+ switch (agen_req->cmd)
+ {
+ case GenerateAddr:
+ {
+ // Load/Store Instruction
+ if (inst->isMemRef()) {
+ DPRINTF(Resource, "[tid:%i] Generating Address for [sn:%i] (%s).\n",
+ tid, inst->seqNum, inst->staticInst->getName());
+
+
+ // We are not handdling Prefetches quite yet
+ if (inst->isDataPrefetch() || inst->isInstPrefetch()) {
+ panic("Prefetches arent handled yet.\n");
+ } else {
+ if (inst->isLoad()) {
+ fault = inst->calcEA();
+ inst->setMemAddr(inst->getEA());
+ //inst->setExecuted();
+
+ DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: "
+ "%#x.\n", tid, inst->seqNum, inst->getEA());
+ } else if (inst->isStore()) {
+ fault = inst->calcEA();
+ inst->setMemAddr(inst->getEA());
+
+ DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: "
+ "%#x.\n", tid, inst->seqNum, inst->getEA());
+ } else {
+ panic("Unexpected memory type!\n");
+ }
+
+ if (fault == NoFault) {
+ agen_req->done();
+ } else {
+ fatal("%s encountered @ [sn:%i]",fault->name(), seq_num);
+ }
+ }
+ } else {
+ DPRINTF(Resource, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num);
+ agen_req->done();
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
diff --git a/src/cpu/inorder/resources/agen_unit.hh b/src/cpu/inorder/resources/agen_unit.hh
new file mode 100644
index 000000000..2010c9fa6
--- /dev/null
+++ b/src/cpu/inorder/resources/agen_unit.hh
@@ -0,0 +1,64 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_AGEN_UNIT_HH__
+#define __CPU_INORDER_AGEN_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/inorder/params.hh"
+
+class AGENUnit : public Resource {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ AGENUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~AGENUnit() {}
+
+ enum Command {
+ GenerateAddr
+ };
+
+ virtual void execute(int slot_num);
+
+ protected:
+ /** @todo: Add Resource Stats Here */
+};
+
+#endif //__CPU_INORDER_DECODE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/bpred_unit.cc b/src/cpu/inorder/resources/bpred_unit.cc
new file mode 100644
index 000000000..66d0779a2
--- /dev/null
+++ b/src/cpu/inorder/resources/bpred_unit.cc
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * 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: Kevin Lim
+ */
+
+#include <list>
+#include <vector>
+
+#include "base/trace.hh"
+#include "base/traceflags.hh"
+#include "cpu/inorder/resources/bpred_unit.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+BPredUnit::BPredUnit(ThePipeline::Params *params)
+ : BTB(params->BTBEntries,
+ params->BTBTagSize,
+ params->instShiftAmt)
+{
+ // Setup the selected predictor.
+ if (params->predType == "local") {
+ localBP = new LocalBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->instShiftAmt);
+ predictor = Local;
+ } else if (params->predType == "tournament") {
+ tournamentBP = new TournamentBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->localHistoryTableSize,
+ params->localHistoryBits,
+ params->globalPredictorSize,
+ params->globalHistoryBits,
+ params->globalCtrBits,
+ params->choicePredictorSize,
+ params->choiceCtrBits,
+ params->instShiftAmt);
+ predictor = Tournament;
+ } else {
+ fatal("Invalid BP selected!");
+ }
+
+ for (int i=0; i < ThePipeline::MaxThreads; i++)
+ RAS[i].init(params->RASSize);
+}
+
+
+void
+BPredUnit::regStats()
+{
+ lookups
+ .name(name() + ".BPredUnit.lookups")
+ .desc("Number of BP lookups")
+ ;
+
+ condPredicted
+ .name(name() + ".BPredUnit.condPredicted")
+ .desc("Number of conditional branches predicted")
+ ;
+
+ condIncorrect
+ .name(name() + ".BPredUnit.condIncorrect")
+ .desc("Number of conditional branches incorrect")
+ ;
+
+ BTBLookups
+ .name(name() + ".BPredUnit.BTBLookups")
+ .desc("Number of BTB lookups")
+ ;
+
+ BTBHits
+ .name(name() + ".BPredUnit.BTBHits")
+ .desc("Number of BTB hits")
+ ;
+
+ BTBCorrect
+ .name(name() + ".BPredUnit.BTBCorrect")
+ .desc("Number of correct BTB predictions (this stat may not "
+ "work properly.")
+ ;
+
+ usedRAS
+ .name(name() + ".BPredUnit.usedRAS")
+ .desc("Number of times the RAS was used to get a target.")
+ ;
+
+ RASIncorrect
+ .name(name() + ".BPredUnit.RASInCorrect")
+ .desc("Number of incorrect RAS predictions.")
+ ;
+}
+
+
+void
+BPredUnit::switchOut()
+{
+ // Clear any state upon switch out.
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
+ squash(0, i);
+ }
+}
+
+
+void
+BPredUnit::takeOverFrom()
+{
+ // Can reset all predictor state, but it's not necessarily better
+ // than leaving it be.
+/*
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i)
+ RAS[i].reset();
+
+ BP.reset();
+ BTB.reset();
+*/
+}
+
+
+bool
+BPredUnit::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
+{
+ // See if branch predictor predicts taken.
+ // If so, get its target addr either from the BTB or the RAS.
+ // Save off record of branch stuff so the RAS can be fixed
+ // up once it's done.
+
+ using TheISA::MachInst;
+
+ bool pred_taken = false;
+ Addr target;
+
+ ++lookups;
+
+ void *bp_history = NULL;
+
+ if (inst->isUncondCtrl()) {
+ DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid);
+ pred_taken = true;
+ // Tell the BP there was an unconditional branch.
+ BPUncond(bp_history);
+
+ if (inst->isReturn() && RAS[tid].empty()) {
+ DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting "
+ "false.\n", tid);
+ pred_taken = false;
+ }
+ } else {
+ ++condPredicted;
+
+ pred_taken = BPLookup(PC, bp_history);
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i "
+ "for PC %#x\n",
+ tid, pred_taken, inst->readPC());
+ }
+
+ PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
+ bp_history, tid);
+
+ // Now lookup in the BTB or RAS.
+ if (pred_taken) {
+ if (inst->isReturn()) {
+ ++usedRAS;
+
+ // If it's a function return call, then look up the address
+ // in the RAS.
+ target = RAS[tid].top();
+
+ // Record the top entry of the RAS, and its index.
+ predict_record.usedRAS = true;
+ predict_record.RASIndex = RAS[tid].topIdx();
+ predict_record.RASTarget = target;
+
+ assert(predict_record.RASIndex < 16);
+
+ RAS[tid].pop();
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, "
+ "RAS predicted target: %#x, RAS index: %i.\n",
+ tid, inst->readPC(), target, predict_record.RASIndex);
+ } else {
+ ++BTBLookups;
+
+ if (inst->isCall()) {
+ RAS[tid].push(PC + sizeof(MachInst));
+
+ // Record that it was a call so that the top RAS entry can
+ // be popped off if the speculation is incorrect.
+ predict_record.wasCall = true;
+
+ DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call"
+ ", adding %#x to the RAS.\n",
+ tid, inst->readPC(), PC + sizeof(MachInst));
+ }
+
+ if (inst->isCall() &&
+ inst->isUncondCtrl() &&
+ inst->isDirectCtrl()) {
+ target = inst->branchTarget();
+
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted"
+ " target to %#x.\n",
+ tid, inst->readPC(), target);
+ } else if (BTB.valid(PC, tid)) {
+ ++BTBHits;
+
+ // If it's not a return, use the BTB to get the target addr.
+ target = BTB.lookup(PC, tid);
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted"
+ " target is %#x.\n",
+ tid, inst->readPC(), target);
+ } else {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a "
+ "valid entry.\n",tid);
+ pred_taken = false;
+ }
+ }
+ }
+
+ if (pred_taken) {
+ // Set the PC and the instruction's predicted target.
+ PC = target;
+ inst->setPredTarg(target);
+ } else {
+ PC = PC + sizeof(MachInst);
+ inst->setPredTarg(PC);
+ }
+
+ predHist[tid].push_front(predict_record);
+
+ DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size());
+
+ inst->setBranchPred(pred_taken);
+
+ return pred_taken;
+}
+
+
+void
+BPredUnit::update(const InstSeqNum &done_sn, unsigned tid)
+{
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Commiting branches until sequence"
+ "number %lli.\n", tid, done_sn);
+
+ while (!predHist[tid].empty() &&
+ predHist[tid].back().seqNum <= done_sn) {
+ // Update the branch predictor with the correct results.
+ BPUpdate(predHist[tid].back().PC,
+ predHist[tid].back().predTaken,
+ predHist[tid].back().bpHistory);
+
+ predHist[tid].pop_back();
+ }
+}
+
+
+void
+BPredUnit::squash(const InstSeqNum &squashed_sn, unsigned tid)
+{
+ History &pred_hist = predHist[tid];
+
+ while (!pred_hist.empty() &&
+ pred_hist.front().seqNum > squashed_sn) {
+ if (pred_hist.front().usedRAS) {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
+ " target: %#x.\n",
+ tid,
+ pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ RAS[tid].restore(pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ } else if (pred_hist.front().wasCall) {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry "
+ "added to the RAS.\n",tid);
+
+ RAS[tid].pop();
+ }
+
+ // This call should delete the bpHistory.
+ BPSquash(pred_hist.front().bpHistory);
+
+ pred_hist.pop_front();
+ }
+
+}
+
+
+void
+BPredUnit::squash(const InstSeqNum &squashed_sn,
+ const Addr &corr_target,
+ const bool actually_taken,
+ unsigned tid)
+{
+ // Now that we know that a branch was mispredicted, we need to undo
+ // all the branches that have been seen up until this branch and
+ // fix up everything.
+
+ History &pred_hist = predHist[tid];
+
+ ++condIncorrect;
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
+ "setting target to %#x.\n",
+ tid, squashed_sn, corr_target);
+
+ squash(squashed_sn, tid);
+
+ // If there's a squash due to a syscall, there may not be an entry
+ // corresponding to the squash. In that case, don't bother trying to
+ // fix up the entry.
+ if (!pred_hist.empty()) {
+ assert(pred_hist.front().seqNum == squashed_sn);
+ if (pred_hist.front().usedRAS) {
+ ++RASIncorrect;
+ }
+
+ BPUpdate(pred_hist.front().PC, actually_taken,
+ pred_hist.front().bpHistory);
+
+ BTB.update(pred_hist.front().PC, corr_target, tid);
+ pred_hist.pop_front();
+ }
+}
+
+
+void
+BPredUnit::BPUncond(void * &bp_history)
+{
+ // Only the tournament predictor cares about unconditional branches.
+ if (predictor == Tournament) {
+ tournamentBP->uncondBr(bp_history);
+ }
+}
+
+
+void
+BPredUnit::BPSquash(void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->squash(bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->squash(bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+bool
+BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history)
+{
+ if (predictor == Local) {
+ return localBP->lookup(inst_PC, bp_history);
+ } else if (predictor == Tournament) {
+ return tournamentBP->lookup(inst_PC, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+void
+BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->update(inst_PC, taken, bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->update(inst_PC, taken, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+void
+BPredUnit::dump()
+{
+ /*typename History::iterator pred_hist_it;
+
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
+ if (!predHist[i].empty()) {
+ pred_hist_it = predHist[i].begin();
+
+ cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
+
+ while (pred_hist_it != predHist[i].end()) {
+ cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
+ "bpHistory:%#x\n",
+ (*pred_hist_it).seqNum, (*pred_hist_it).PC,
+ (*pred_hist_it).tid, (*pred_hist_it).predTaken,
+ (*pred_hist_it).bpHistory);
+ pred_hist_it++;
+ }
+
+ cprintf("\n");
+ }
+ }*/
+}
diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh
new file mode 100644
index 000000000..b945922a7
--- /dev/null
+++ b/src/cpu/inorder/resources/bpred_unit.hh
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * 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: Kevin Lim
+ * Korey Sewell
+ */
+
+#ifndef __CPU_INORDER_BPRED_UNIT_HH__
+#define __CPU_INORDER_BPRED_UNIT_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "cpu/inst_seq.hh"
+
+//#include "cpu/inorder/params.hh"
+#include "cpu/o3/2bit_local_pred.hh"
+#include "cpu/o3/btb.hh"
+#include "cpu/o3/ras.hh"
+#include "cpu/o3/tournament_pred.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+#include <list>
+
+/**
+ * Basically a wrapper class to hold both the branch predictor
+ * and the BTB.
+ */
+class BPredUnit
+{
+ private:
+
+ enum PredType {
+ Local,
+ Tournament
+ };
+
+ PredType predictor;
+
+ public:
+
+ /**
+ * @param params The params object, that has the size of the BP and BTB.
+ */
+ BPredUnit(ThePipeline::Params *params);
+
+ /**
+ * Registers statistics.
+ */
+ void regStats();
+
+ void switchOut();
+
+ void takeOverFrom();
+
+ /**
+ * Predicts whether or not the instruction is a taken branch, and the
+ * target of the branch if it is taken.
+ * @param inst The branch instruction.
+ * @param PC The predicted PC is passed back through this parameter.
+ * @param tid The thread id.
+ * @return Returns if the branch is taken or not.
+ */
+ bool predict(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid);
+
+ // @todo: Rename this function.
+ void BPUncond(void * &bp_history);
+
+ /**
+ * Tells the branch predictor to commit any updates until the given
+ * sequence number.
+ * @param done_sn The sequence number to commit any older updates up until.
+ * @param tid The thread id.
+ */
+ void update(const InstSeqNum &done_sn, unsigned tid);
+
+ /**
+ * Squashes all outstanding updates until a given sequence number.
+ * @param squashed_sn The sequence number to squash any younger updates up
+ * until.
+ * @param tid The thread id.
+ */
+ void squash(const InstSeqNum &squashed_sn, unsigned tid);
+
+ /**
+ * Squashes all outstanding updates until a given sequence number, and
+ * corrects that sn's update with the proper address and taken/not taken.
+ * @param squashed_sn The sequence number to squash any younger updates up
+ * until.
+ * @param corr_target The correct branch target.
+ * @param actually_taken The correct branch direction.
+ * @param tid The thread id.
+ */
+ void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
+ bool actually_taken, unsigned tid);
+
+ /**
+ * @param bp_history Pointer to the history object. The predictor
+ * will need to update any state and delete the object.
+ */
+ void BPSquash(void *bp_history);
+
+ /**
+ * Looks up a given PC in the BP to see if it is taken or not taken.
+ * @param inst_PC The PC to look up.
+ * @param bp_history Pointer that will be set to an object that
+ * has the branch predictor state associated with the lookup.
+ * @return Whether the branch is taken or not taken.
+ */
+ bool BPLookup(Addr &inst_PC, void * &bp_history);
+
+ /**
+ * Looks up a given PC in the BTB to see if a matching entry exists.
+ * @param inst_PC The PC to look up.
+ * @return Whether the BTB contains the given PC.
+ */
+ bool BTBValid(Addr &inst_PC)
+ { return BTB.valid(inst_PC, 0); }
+
+ /**
+ * Looks up a given PC in the BTB to get the predicted target.
+ * @param inst_PC The PC to look up.
+ * @return The address of the target of the branch.
+ */
+ Addr BTBLookup(Addr &inst_PC)
+ { return BTB.lookup(inst_PC, 0); }
+
+ /**
+ * Updates the BP with taken/not taken information.
+ * @param inst_PC The branch's PC that will be updated.
+ * @param taken Whether the branch was taken or not taken.
+ * @param bp_history Pointer to the branch predictor state that is
+ * associated with the branch lookup that is being updated.
+ * @todo Make this update flexible enough to handle a global predictor.
+ */
+ void BPUpdate(Addr &inst_PC, bool taken, void *bp_history);
+
+ /**
+ * Updates the BTB with the target of a branch.
+ * @param inst_PC The branch's PC that will be updated.
+ * @param target_PC The branch's target that will be added to the BTB.
+ */
+ void BTBUpdate(Addr &inst_PC, Addr &target_PC)
+ { BTB.update(inst_PC, target_PC,0); }
+
+ void dump();
+
+ private:
+ struct PredictorHistory {
+ /**
+ * Makes a predictor history struct that contains any
+ * information needed to update the predictor, BTB, and RAS.
+ */
+ PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
+ const bool pred_taken, void *bp_history,
+ const unsigned _tid)
+ : seqNum(seq_num), PC(inst_PC), RASTarget(0),
+ RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0),
+ wasCall(0), bpHistory(bp_history)
+ { }
+
+ /** The sequence number for the predictor history entry. */
+ InstSeqNum seqNum;
+
+ /** The PC associated with the sequence number. */
+ Addr PC;
+
+ /** The RAS target (only valid if a return). */
+ Addr RASTarget;
+
+ /** The RAS index of the instruction (only valid if a call). */
+ unsigned RASIndex;
+
+ /** The thread id. */
+ unsigned tid;
+
+ /** Whether or not it was predicted taken. */
+ bool predTaken;
+
+ /** Whether or not the RAS was used. */
+ bool usedRAS;
+
+ /** Whether or not the instruction was a call. */
+ bool wasCall;
+
+ /** Pointer to the history object passed back from the branch
+ * predictor. It is used to update or restore state of the
+ * branch predictor.
+ */
+ void *bpHistory;
+ };
+
+ typedef std::list<PredictorHistory> History;
+
+ /**
+ * The per-thread predictor history. This is used to update the predictor
+ * as instructions are committed, or restore it to the proper state after
+ * a squash.
+ */
+ History predHist[ThePipeline::MaxThreads];
+
+ /** The local branch predictor. */
+ LocalBP *localBP;
+
+ /** The tournament branch predictor. */
+ TournamentBP *tournamentBP;
+
+ /** The BTB. */
+ DefaultBTB BTB;
+
+ /** The per-thread return address stack. */
+ ReturnAddrStack RAS[ThePipeline::MaxThreads];
+
+ /** Stat for number of BP lookups. */
+ Stats::Scalar<> lookups;
+ /** Stat for number of conditional branches predicted. */
+ Stats::Scalar<> condPredicted;
+ /** Stat for number of conditional branches predicted incorrectly. */
+ Stats::Scalar<> condIncorrect;
+ /** Stat for number of BTB lookups. */
+ Stats::Scalar<> BTBLookups;
+ /** Stat for number of BTB hits. */
+ Stats::Scalar<> BTBHits;
+ /** Stat for number of times the BTB is correct. */
+ Stats::Scalar<> BTBCorrect;
+ /** Stat for number of times the RAS is used to get a target. */
+ Stats::Scalar<> usedRAS;
+ /** Stat for number of times the RAS is incorrect. */
+ Stats::Scalar<> RASIncorrect;
+};
+
+#endif // __CPU_INORDER_BPRED_UNIT_HH__
diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc
new file mode 100644
index 000000000..b563a3057
--- /dev/null
+++ b/src/cpu/inorder/resources/branch_predictor.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 "cpu/inorder/resources/branch_predictor.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ branchPred(params)
+{
+ instSize = sizeof(MachInst);
+}
+
+void
+BranchPredictor::regStats()
+{
+ predictedTaken
+ .name(name() + ".predictedTaken")
+ .desc("Number of Branches Predicted As Taken (True).");
+
+ predictedNotTaken
+ .name(name() + ".predictedNotTaken")
+ .desc("Number of Branches Predicted As Not Taken (False).");
+
+ Resource::regStats();
+}
+
+void
+BranchPredictor::execute(int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ ResourceRequest* bpred_req = reqMap[slot_num];
+
+ DynInstPtr inst = bpred_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ //int stage_num = bpred_req->getStageNum();
+
+ bpred_req->fault = NoFault;
+
+ switch (bpred_req->cmd)
+ {
+ case PredictBranch:
+ {
+ Addr pred_PC = inst->readNextPC();
+
+ if (inst->isControl()) {
+ // If predicted, the pred_PC will be updated to new target value
+ // If not, the pred_PC be updated to pc+8
+ bool predict_taken = branchPred.predict(inst, pred_PC, tid);
+
+ if (predict_taken) {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n",
+ tid, seq_num);
+
+ inst->setPredTarg(pred_PC);
+
+ predictedTaken++;
+ } else {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted false.\n",
+ tid, seq_num);
+
+ if (inst->isCondDelaySlot())
+ {
+ inst->setPredTarg(inst->readPC() + (2 * instSize));
+ } else {
+ inst->setPredTarg(pred_PC);
+ }
+
+ predictedNotTaken++;
+ }
+
+ inst->setBranchPred(predict_taken);
+
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n",
+ tid, seq_num, pred_PC);
+
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Ignoring [sn:%i] because this isn't "
+ "a control instruction.\n", tid, seq_num);
+ }
+
+ bpred_req->done();
+ }
+ break;
+
+ case UpdatePredictor:
+ {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n",
+ tid, seq_num);
+
+
+ branchPred.update(seq_num, tid);
+
+ bpred_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+void
+BranchPredictor::squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(Resource, "Squashing...\n");
+ branchPred.squash(squash_seq_num, tid);
+}
+
+void
+BranchPredictor::instGraduated(InstSeqNum seq_num,unsigned tid)
+{
+ branchPred.update(seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/branch_predictor.hh b/src/cpu/inorder/resources/branch_predictor.hh
new file mode 100644
index 000000000..66eb1afe8
--- /dev/null
+++ b/src/cpu/inorder/resources/branch_predictor.hh
@@ -0,0 +1,87 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_BRANCH_PREDICTOR_HH__
+#define __CPU_INORDER_BRANCH_PREDICTOR_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/bpred_unit.hh"
+#include "cpu/inorder/cpu.hh"
+//#include "cpu/inorder/params.hh"
+
+class BranchPredictor : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ PredictBranch,
+ UpdatePredictor
+ };
+
+ public:
+ BranchPredictor(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+
+ virtual void regStats();
+
+ virtual void execute(int slot_num);
+
+ virtual void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+
+ virtual void instGraduated(InstSeqNum seq_num,unsigned tid);
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ BPredUnit branchPred;
+
+ int instSize;
+
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ Stats::Scalar<> predictedTaken;
+ Stats::Scalar<> predictedNotTaken;
+
+};
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc
new file mode 100644
index 000000000..79ca7a096
--- /dev/null
+++ b/src/cpu/inorder/resources/cache_unit.cc
@@ -0,0 +1,609 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "arch/mips/locked_mem.hh"
+#include "arch/utility.hh"
+#include "cpu/inorder/resources/cache_unit.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "mem/request.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+
+Tick
+CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("DefaultFetch doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
+void
+CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
+{
+ panic("DefaultFetch doesn't expect recvFunctional callback!");
+}
+
+void
+CacheUnit::CachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("DefaultFetch doesn't expect recvStatusChange callback!");
+}
+
+bool
+CacheUnit::CachePort::recvTiming(Packet *pkt)
+{
+ cachePortUnit->processCacheCompletion(pkt);
+ return true;
+}
+
+void
+CacheUnit::CachePort::recvRetry()
+{
+ cachePortUnit->recvRetry();
+}
+
+CacheUnit::CacheUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ retryPkt(NULL), retrySlot(-1)
+{
+ //cacheData.resize(res_width);
+ //slotStatus = new CachePortStatus[width];
+ //fetchPC = new Addr[width];
+ cachePort = new CachePort(this);
+
+ cacheBlocked = false;
+}
+
+
+Port *
+CacheUnit::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == resName)
+ return cachePort;
+ else
+ return NULL;
+}
+
+int
+CacheUnit::getSlot(DynInstPtr inst)
+{
+ if (!inst->validMemAddr()) {
+ panic("Mem. Addr. must be set before requesting cache access.\n");
+ }
+
+ Addr req_addr = inst->getMemAddr();
+
+ if (resName == "icache_port" ||
+ find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) {
+
+ int new_slot = Resource::getSlot(inst);
+
+ if (new_slot != -1) {
+ inst->memTime = curTick;
+ addrList.push_back(req_addr);
+ addrMap[req_addr] = inst->seqNum;
+ DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Address %08p added to dependency list.\n",
+ inst->readTid(), inst->seqNum, req_addr);
+ return new_slot;
+ } else {
+ return -1;
+ }
+
+
+ } else {
+ DPRINTF(InOrderCachePort,"Denying request because there is an outstanding"
+ " request to/for addr. %08p. by [sn:%i] @ tick %i\n",
+ req_addr, addrMap[req_addr], inst->memTime);
+ return -1;
+ }
+}
+
+void
+CacheUnit::freeSlot(int slot_num)
+{
+ std::vector<Addr>::iterator vect_it = find(addrList.begin(), addrList.end(),
+ reqMap[slot_num]->inst->getMemAddr());
+ assert(vect_it != addrList.end());
+
+ DPRINTF(InOrderCachePort, "[tid:%i]: Address %08p removed from dependency list.\n",
+ reqMap[slot_num]->inst->readTid(), (*vect_it));
+
+ addrList.erase(vect_it);
+
+ Resource::freeSlot(slot_num);
+}
+
+ResReqPtr
+CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd)
+{
+ ScheduleEntry* sched_entry = inst->resSched.top();
+
+ if (!inst->validMemAddr()) {
+ panic("Mem. Addr. must be set before requesting cache access.\n");
+ }
+
+ int req_size = 0;
+ MemCmd::Command pkt_cmd;
+
+ if (sched_entry->cmd == InitiateReadData) {
+ pkt_cmd = MemCmd::ReadReq;
+ req_size = inst->getMemAccSize();
+
+ DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p.\n",
+ inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
+ } else if (sched_entry->cmd == InitiateWriteData) {
+ pkt_cmd = MemCmd::WriteReq;
+ req_size = inst->getMemAccSize();
+
+
+ DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p.\n",
+ inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
+ } else if (sched_entry->cmd == InitiateFetch){
+ pkt_cmd = MemCmd::ReadReq;
+ req_size = sizeof(MachInst); //@TODO: mips16e
+
+ DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p.\n",
+ inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
+ } else {
+ panic("%i: Unexpected request type (%i) to %s", curTick, sched_entry->cmd, name());
+ }
+
+ return new CacheRequest(this, inst, stage_num, id, slot_num,
+ sched_entry->cmd, req_size, pkt_cmd,
+ 0/*flags*/, this->cpu->readCpuId());
+}
+
+void
+CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
+{
+ //service_request = false;
+
+ CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
+ assert(cache_req);
+
+ // Check to see if this instruction is requesting the same command
+ // or a different one
+ if (cache_req->cmd != inst->resSched.top()->cmd) {
+ // If different, then update command in the request
+ cache_req->cmd = inst->resSched.top()->cmd;
+ DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Updating the command for this "
+ "instruction.\n", inst->readTid(), inst->seqNum);
+
+ service_request = true;
+ } else {
+ // If same command, just check to see if memory access was completed
+ // but dont try to re-execute
+ DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: requesting this resource again.\n",
+ inst->readTid(), inst->seqNum);
+
+ service_request = true;
+ }
+
+}
+
+void
+CacheUnit::execute(int slot_num)
+{
+ if (cacheBlocked) {
+ DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access.\n");
+ return;
+ }
+
+ CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
+ assert(cache_req);
+
+ DynInstPtr inst = cache_req->inst;
+ int tid;
+ tid = inst->readTid();
+ int seq_num;
+ seq_num = inst->seqNum;
+ //int stage_num = cache_req->getStageNum();
+
+ cache_req->fault = NoFault;
+
+ switch (cache_req->cmd)
+ {
+ case InitiateFetch:
+ {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
+ tid, name(), cache_req->inst->getMemAddr());
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: Fetching new cache block from addr: %08p\n",
+ tid, cache_req->memReq->getVaddr());
+
+ inst->setCurResSlot(slot_num);
+ doDataAccess(inst);
+ }
+ break;
+
+ case CompleteFetch:
+ {
+ if (cache_req->isMemAccComplete()) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: Completing Fetch Access for [sn:%i]\n",
+ tid, inst->seqNum);
+
+ MachInst mach_inst = cache_req->dataPkt->get<MachInst>();
+
+ //@TODO: May Need This Function for Endianness-Compatibility
+ //mach_inst = gtoh(*reinterpret_cast<MachInst *>(&cacheData[tid][offset]));
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: Fetched instruction is %08p\n",
+ tid, mach_inst);
+
+ //ExtMachInst ext_inst
+ // = TheISA::makeExtMI(mach_inst, cpu->tcBase(tid));
+
+ inst->setMachInst(mach_inst);
+ inst->setASID(tid);
+ inst->setThreadState(cpu->thread[tid]);
+
+ DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n",
+ tid, seq_num, inst->staticInst->disassemble(inst->PC));
+
+ // Set Up More TraceData info
+ if (inst->traceData) {
+ inst->traceData->setStaticInst(inst->staticInst);
+ inst->traceData->setPC(inst->readPC());
+ }
+
+ cache_req->done();
+ } else {
+ DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access.\n",
+ tid, inst->seqNum);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: Fetch miss from %08p.\n",
+ tid, cache_req->inst->readPC());
+ cache_req->setCompleted(false);
+ }
+ }
+ break;
+
+ case InitiateReadData:
+ case InitiateWriteData:
+ {
+ DPRINTF(InOrderCachePort, "[tid:%u]: Initiating data access to %s "
+ "for addr. %08p\n",
+ tid, name(), cache_req->inst->getMemAddr());
+
+ inst->setCurResSlot(slot_num);
+ //inst->memAccess();
+ inst->initiateAcc();
+ }
+ break;
+
+ case CompleteReadData:
+ case CompleteWriteData:
+ {
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: [sn:%i]: Trying to Complete Data Access.\n",
+ tid, inst->seqNum);
+ if (cache_req->isMemAccComplete()) {
+ cache_req->done();
+ } else {
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
+ tid, cache_req->inst->getMemAddr());
+ cache_req->setCompleted(false);
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+Fault
+CacheUnit::doDataAccess(DynInstPtr inst)
+{
+ Fault fault = NoFault;
+ int tid = 0;
+
+ tid = inst->readTid();
+
+ CacheReqPtr cache_req
+ = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
+ assert(cache_req);
+
+ cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd,
+ Packet::Broadcast);
+
+ if (cache_req->dataPkt->isRead()) {
+ cache_req->dataPkt->dataStatic(cache_req->reqData);
+ } else if (cache_req->dataPkt->isWrite()) {
+ cache_req->dataPkt->dataStatic(&cache_req->inst->storeData);
+
+ }
+
+ cache_req->dataPkt->time = curTick;
+
+ bool do_access = true; // flag to suppress cache access
+
+ Request *memReq = cache_req->dataPkt->req;
+
+ if (cache_req->dataPkt->isWrite() && memReq->isLocked()) {
+ assert(cache_req->inst->isStoreConditional());
+ DPRINTF(InOrderCachePort, "Evaluating Store Conditional access.\n");
+ do_access = TheISA::handleLockedWrite(cpu, memReq);
+ }
+
+
+ DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] attempting to access cache..\n", tid, inst->seqNum);
+
+ //@TODO: If you want to ignore failed store conditional accesses, then
+ // enable this. However, this might skew memory stats because
+ // the failed store conditional access will get ignored.
+ // - Remove optionality here ...
+ if (1/*do_access*/) {
+ if (!cachePort->sendTiming(cache_req->dataPkt)) {
+ DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is waiting to retry request.\n", tid, inst->seqNum);
+
+ retrySlot = cache_req->getSlot();
+ retryReq = cache_req;
+ retryPkt = cache_req->dataPkt;
+
+ cacheStatus = cacheWaitRetry;
+
+ //cacheBlocked = true;
+
+ DPRINTF(InOrderStall, "STALL: \n");
+
+ cache_req->setCompleted(false);
+ } else {
+ DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is now waiting for cache response.\n", tid, inst->seqNum);
+ cache_req->setCompleted();
+ cache_req->setMemAccPending();
+ cacheStatus = cacheWaitResponse;
+ cacheBlocked = false;
+ }
+ } else if (!do_access && memReq->isLocked()){
+ // Store-Conditional instructions complete even if they "failed"
+ assert(cache_req->inst->isStoreConditional());
+ cache_req->setCompleted(true);
+
+ DPRINTF(LLSC, "[tid:%i]: T%i Ignoring Failed Store Conditional Access.\n",
+ tid, tid);
+
+ cache_req->dataPkt->req->setExtraData(0);
+
+ processCacheCompletion(cache_req->dataPkt);
+
+ // Automatically set these since we ignored the memory access
+ //cache_req->setMemAccPending(false);
+ //cache_req->setMemAccCompleted();
+ } else {
+ // Make cache request again since access due to
+ // inability to access
+ DPRINTF(InOrderStall, "STALL: \n");
+ cache_req->setCompleted(false);
+ }
+
+ return fault;
+}
+
+void
+CacheUnit::processCacheCompletion(PacketPtr pkt)
+{
+ // Cast to correct packet type
+ CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
+ assert(cache_pkt);
+
+ if (cache_pkt->cacheReq->isSquashed()) {
+ DPRINTF(InOrderCachePort,
+ "Ignoring completion of squashed access, [tid:%i] [sn:%i].\n",
+ cache_pkt->cacheReq->getInst()->readTid(),
+ cache_pkt->cacheReq->getInst()->seqNum);
+
+ cache_pkt->cacheReq->done();
+ return;
+ } else {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p.\n",
+ cache_pkt->cacheReq->getInst()->readTid(),
+ cache_pkt->cacheReq->getInst()->seqNum,
+ cache_pkt->cacheReq->getInst()->getMemAddr());
+ }
+
+ // Cast to correct request type
+ CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
+ findRequest(cache_pkt->cacheReq->getInst()));
+ assert(cache_req);
+
+#if TRACING_ON
+ // Get resource request info
+ unsigned tid = 0;
+#endif
+
+ //tid = pkt->req->getThreadNum();
+ unsigned stage_num = cache_req->getStageNum();
+ DynInstPtr inst = cache_req->inst;
+
+ if (!cache_req->isSquashed()) {
+ if (inst->resSched.top()->cmd == CompleteFetch) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Processing fetch access.\n",
+ tid, inst->seqNum);
+ } else if (inst->staticInst && inst->isMemRef()) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Processing cache access.\n",
+ tid, inst->seqNum);
+
+ inst->completeAcc(pkt);
+
+ if (inst->isLoad()) {
+ assert(cache_pkt->isRead());
+
+ if (cache_pkt->req->isLocked()) {
+ DPRINTF(InOrderCachePort, "[tid:%u]: Handling Load-Linked "
+ "access for [sn:%u].\n", tid, inst->seqNum);
+ TheISA::handleLockedRead(cpu, cache_pkt->req);
+ }
+
+ // @TODO: Hardcoded to for load instructions. Assumes that
+ // the dest. idx 0 is always where the data is loaded to.
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Data loaded was: %08p.\n",
+ tid, inst->seqNum, inst->readIntResult(0));
+ } else if(inst->isStore()) {
+ assert(cache_pkt->isWrite());
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Data stored was: %08p.\n",
+ tid, inst->seqNum,
+ getMemData(cache_pkt));
+
+ }
+ }
+
+ cache_req->setMemAccPending(false);
+ cache_req->setMemAccCompleted();
+
+ // Wake up the CPU (if it went to sleep and was waiting on this
+ // completion event).
+ cpu->wakeCPU();
+
+ DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n",
+ tid, cpu->pipelineStage[stage_num]->name());
+
+ cpu->switchToActive(stage_num);
+ } else {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u] Cache miss on memory access to block @ %08p "
+ "completed, but squashed.\n", tid, cache_req->inst->readPC());
+ cache_req->setMemAccCompleted();
+ }
+
+ inst->unsetMemAddr();
+}
+
+void
+CacheUnit::recvRetry()
+{
+ DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i].\n",
+ retryReq->inst->readTid(), retryReq->inst->seqNum);
+
+ assert(retryPkt != NULL);
+ assert(cacheBlocked);
+ assert(cacheStatus == cacheWaitRetry);
+
+ if (cachePort->sendTiming(retryPkt)) {
+ cacheStatus = cacheWaitResponse;
+ retryPkt = NULL;
+ cacheBlocked = false;
+ } else {
+ DPRINTF(InOrderCachePort, "Retry Request for [tid:%i] [sn:%i] failed.\n",
+ retryReq->inst->readTid(), retryReq->inst->seqNum);
+ }
+
+}
+
+void
+CacheUnit::squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ std::vector<int> slot_remove_list;
+
+ std::map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ std::map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ ResReqPtr req_ptr = (*map_it).second;
+
+ if (req_ptr &&
+ req_ptr->getInst()->readTid() == tid &&
+ req_ptr->getInst()->seqNum > squash_seq_num) {
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i] Squashing request from [sn:%i].\n",
+ req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
+
+ req_ptr->setSquashed();
+
+ req_ptr->getInst()->setSquashed();
+
+ CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr);
+ assert(cache_req);
+
+ if (!cache_req->isMemAccPending()) {
+ // Mark request for later removal
+ cpu->reqRemoveList.push(req_ptr);
+
+ // Mark slot for removal from resource
+ slot_remove_list.push_back(req_ptr->getSlot());
+ }
+ }
+
+ map_it++;
+ }
+
+ // Now Delete Slot Entry from Req. Map
+ for (int i = 0; i < slot_remove_list.size(); i++) {
+ freeSlot(slot_remove_list[i]);
+ }
+
+}
+
+uint64_t CacheUnit::getMemData(Packet *packet) {
+ switch (packet->getSize())
+ {
+ case 8:
+ return packet->get<uint8_t>();
+
+ case 16:
+ return packet->get<uint16_t>();
+
+ case 32:
+ return packet->get<uint32_t>();
+
+ case 864:
+ return packet->get<uint64_t>();
+
+ default:
+ std::cerr << "bad store data size = " << packet->getSize() << std::endl;
+
+ assert(0);
+ return 0;
+ }
+}
+
diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh
new file mode 100644
index 000000000..9d048d789
--- /dev/null
+++ b/src/cpu/inorder/resources/cache_unit.hh
@@ -0,0 +1,305 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_CACHE_UNIT_HH__
+#define __CPU_INORDER_CACHE_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+//#include "cpu/inorder/params.hh"
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "mem/port.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "sim/sim_object.hh"
+
+#include "params/InOrderCPU.hh"
+
+class CacheRequest;
+typedef CacheRequest* CacheReqPtr;
+
+class CacheReqPacket;
+typedef CacheReqPacket* CacheReqPktPtr;
+
+class CacheUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ CacheUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~CacheUnit() {}
+
+ enum Command {
+ InitiateFetch,
+ CompleteFetch,
+ InitiateReadData,
+ CompleteReadData,
+ InitiateWriteData,
+ CompleteWriteData,
+ Fetch,
+ ReadData,
+ WriteData
+ };
+
+ public:
+ /** CachePort class for the Cache Unit. Handles doing the
+ * communication with the cache/memory.
+ */
+ class CachePort : public Port
+ {
+ protected:
+ /** Pointer to cache port unit */
+ CacheUnit *cachePortUnit;
+
+ public:
+ /** Default constructor. */
+ CachePort(CacheUnit *_cachePortUnit)
+ : Port(_cachePortUnit->name() + "-cache-port", (MemObject*)_cachePortUnit->cpu),
+ cachePortUnit(_cachePortUnit)
+ { }
+
+ bool snoopRangeSent;
+
+ protected:
+ /** Atomic version of receive. Panics. */
+ virtual Tick recvAtomic(PacketPtr pkt);
+
+ /** Functional version of receive. Panics. */
+ virtual void recvFunctional(PacketPtr pkt);
+
+ /** Receives status change. Other than range changing, panics. */
+ virtual void recvStatusChange(Status status);
+
+ /** Returns the address ranges of this device. */
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { resp.clear(); snoop.clear(); }
+
+ /** Timing version of receive. Handles setting fetch to the
+ * proper status to start fetching. */
+ virtual bool recvTiming(PacketPtr pkt);
+
+ /** Handles doing a retry of a failed fetch. */
+ virtual void recvRetry();
+ };
+
+ enum CachePortStatus {
+ cacheWaitResponse,
+ cacheWaitRetry,
+ cacheAccessComplete
+ };
+
+ ///virtual void init();
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ void requestAgain(DynInstPtr inst, bool &try_request);
+
+ int getSlot(DynInstPtr inst);
+
+ void freeSlot(int slot_num);
+
+ /** Execute the function of this resource. The Default is action
+ * is to do nothing. More specific models will derive from this
+ * class and define their own execute function.
+ */
+ void execute(int slot_num);
+
+ void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+
+ /** Processes cache completion event. */
+ void processCacheCompletion(PacketPtr pkt);
+
+ void recvRetry();
+
+ /** Align a PC to the start of an I-cache block. */
+ Addr cacheBlockAlignPC(Addr addr)
+ {
+ //addr = TheISA::realPCToFetchPC(addr);
+ return (addr & ~(cacheBlkMask));
+ }
+
+ /** Returns a specific port. */
+ Port *getPort(const std::string &if_name, int idx);
+
+ /** Fetch on behalf of an instruction. Will check to see
+ * if instruction is actually in resource before
+ * trying to fetch.
+ */
+ //Fault doFetchAccess(DynInstPtr inst);
+
+ /** Read/Write on behalf of an instruction.
+ * curResSlot needs to be a valid value in instruction.
+ */
+ Fault doDataAccess(DynInstPtr inst);
+
+ uint64_t getMemData(Packet *packet);
+
+ protected:
+ /** Cache interface. */
+ CachePort *cachePort;
+
+ CachePortStatus cacheStatus;
+
+ CacheReqPtr retryReq;
+
+ PacketPtr retryPkt;
+
+ int retrySlot;
+
+ bool cacheBlocked;
+
+ std::vector<Addr> addrList;
+
+ std::map<Addr, InstSeqNum> addrMap;
+
+ public:
+ int cacheBlkSize;
+
+ int cacheBlkMask;
+
+ /** Align a PC to the start of the Cache block. */
+ Addr cacheBlockAlign(Addr addr)
+ {
+ return (addr & ~(cacheBlkMask));
+ }
+
+ /** THINGS USED FOR FETCH */
+ // NO LONGER USED BY COMMENT OUT UNTIL FULL VERIFICATION
+ /** The mem line being fetched. */
+ //uint8_t *cacheData[ThePipeline::MaxThreads];
+
+ /** The Addr of the cacheline that has been loaded. */
+ //Addr cacheBlockAddr[ThePipeline::MaxThreads];
+
+ //unsigned fetchOffset[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+};
+
+struct CacheSchedEntry : public ThePipeline::ScheduleEntry {
+ enum EntryType {
+ FetchAccess,
+ DataAccess
+ };
+
+ CacheSchedEntry(int stage_num, int _priority, int res_num, MemCmd::Command pkt_cmd,
+ EntryType _type = FetchAccess) :
+ ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd),
+ type(_type)
+ { }
+
+ MemCmd::Command pktCmd;
+ EntryType type;
+};
+
+class CacheRequest : public ResourceRequest {
+ public:
+ CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd, int req_size,
+ MemCmd::Command pkt_cmd, unsigned flags, int cpu_id)
+ : ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd),
+ pktCmd(pkt_cmd), memAccComplete(false), memAccPending(false)
+ {
+ memReq = inst->memReq;
+
+ reqData = new uint8_t[req_size];
+ retryPkt = NULL;
+ }
+
+ virtual ~CacheRequest()
+ {
+ /*
+ delete reqData;
+
+ Can get rid of packet and packet request now
+ if (*dataPkt) {
+ if (*dataPkt->req) {
+ delete dataPkt->req;
+ }
+ delete dataPkt;
+ }
+
+ // Can get rid of packet and packet request now
+ if (retryPkt) {
+ if (retryPkt->req) {
+ delete retryPkt->req;
+ }
+ delete retryPkt;
+ }*/
+
+ if (memReq) {
+ delete memReq;
+ }
+ }
+
+ virtual PacketDataPtr getData()
+ { return reqData; }
+
+ void setMemAccCompleted(bool completed = true) { memAccComplete = completed; }
+ bool isMemAccComplete() { return memAccComplete; }
+
+ void setMemAccPending(bool pending = true) { memAccPending = pending; }
+ bool isMemAccPending() { return memAccPending; }
+
+ //Make this data private/protected!
+ MemCmd::Command pktCmd;
+ RequestPtr memReq;
+ PacketDataPtr reqData;
+ PacketPtr dataPkt;
+ PacketPtr retryPkt;
+
+ bool memAccComplete;
+ bool memAccPending;
+};
+
+class CacheReqPacket : public Packet {
+ public:
+ CacheReqPacket(CacheRequest *_req,
+ Command _cmd, short _dest)
+ : Packet(_req->memReq, _cmd, _dest), cacheReq(_req)
+ {
+
+ }
+
+ CacheRequest *cacheReq;
+};
+
+#endif //__CPU_CACHE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc
new file mode 100644
index 000000000..1628c32d0
--- /dev/null
+++ b/src/cpu/inorder/resources/decode_unit.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 "cpu/inorder/resources/decode_unit.hh"
+
+using namespace TheISA;
+using namespace ThePipeline;
+using namespace std;
+
+DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{
+ for (int tid = 0; tid < MaxThreads; tid++) {
+ regDepMap[tid] = &cpu->archRegDepMap[tid];
+ }
+}
+
+void
+DecodeUnit::execute(int slot_num)
+{
+ ResourceRequest* decode_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid, seq_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ decode_req->fault = NoFault;
+
+ switch (decode_req->cmd)
+ {
+ case DecodeInst:
+ {
+ bool done_sked = ThePipeline::createBackEndSchedule(inst);
+
+ if (done_sked) {
+ DPRINTF(Resource, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n",
+ tid, seq_num);
+ regDepMap[tid]->insert(inst);
+ decode_req->done();
+ } else {
+ DPRINTF(Resource,"[tid:%i] Static Inst not available to decode. Unable to create "
+ "schedule for instruction [sn:%i] \n", tid, inst->seqNum);
+ DPRINTF(InOrderStall, "STALL: \n");
+ decode_req->done(false);
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+
+void
+DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n",
+ tid, stage_num, squash_seq_num);
+
+ //cpu->removeInstsUntil(squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/decode_unit.hh b/src/cpu/inorder/resources/decode_unit.hh
new file mode 100644
index 000000000..3813de6c4
--- /dev/null
+++ b/src/cpu/inorder/resources/decode_unit.hh
@@ -0,0 +1,68 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_DECODE_UNIT_HH__
+#define __CPU_INORDER_DECODE_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+
+class DecodeUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ DecodeUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~DecodeUnit() {}
+
+ enum Command {
+ DecodeInst
+ };
+
+ virtual void execute(int slot_num);
+
+ void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ RegDepMap *regDepMap[ThePipeline::MaxThreads];
+
+ protected:
+ /** @todo: Add Resource Stats Here */
+};
+
+#endif //__CPU_INORDER_DECODE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc
new file mode 100644
index 000000000..e41291103
--- /dev/null
+++ b/src/cpu/inorder/resources/execution_unit.cc
@@ -0,0 +1,182 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "cpu/inorder/resources/execution_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+ExecutionUnit::regStats()
+{
+ predictedTakenIncorrect
+ .name(name() + ".predictedTakenIncorrect")
+ .desc("Number of Branches Incorrectly Predicted As Taken.");
+
+ predictedNotTakenIncorrect
+ .name(name() + ".predictedNotTakenIncorrect")
+ .desc("Number of Branches Incorrectly Predicted As Not Taken).");
+
+ Resource::regStats();
+}
+
+void
+ExecutionUnit::execute(int slot_num)
+{
+ ResourceRequest* exec_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+
+ exec_req->fault = NoFault;
+
+ DPRINTF(Resource, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n",
+ tid, seq_num, inst->readPC());
+
+ switch (exec_req->cmd)
+ {
+ case ExecuteInst:
+ {
+ if (inst->isMemRef()) {
+ fatal("%s not configured to handle memory ops.\n", resName);
+ } else if (inst->isControl()) {
+ // Evaluate Branch
+ fault = inst->execute();
+
+ inst->setExecuted();
+
+ if (fault == NoFault) {
+ // If branch is mispredicted, then signal squash
+ // throughout all stages behind the pipeline stage
+ // that got squashed.
+ if (inst->mispredicted()) {
+ int stage_num = exec_req->getStageNum();
+ int tid = inst->readTid();
+
+ // If it's a branch ...
+ if (inst->isDirectCtrl()) {
+ assert(!inst->isIndirectCtrl());
+
+ if (inst->predTaken() && inst->isCondDelaySlot()) {
+ inst->bdelaySeqNum = seq_num;
+ inst->setPredTarg(inst->nextPC);
+
+ DPRINTF(Resource, "[tid:%i]: Conditional branch inst"
+ "[sn:%i] PC %#x mispredicted as taken.\n", tid,
+ seq_num, inst->PC);
+ } else if (!inst->predTaken() && inst->isCondDelaySlot()) {
+ inst->bdelaySeqNum = seq_num;
+ inst->setPredTarg(inst->nextPC);
+ inst->procDelaySlotOnMispred = true;
+
+ DPRINTF(Resource, "[tid:%i]: Conditional branch inst."
+ "[sn:%i] PC %#x mispredicted as not taken.\n", tid,
+ seq_num, inst->PC);
+ } else {
+ inst->bdelaySeqNum = seq_num + 1;
+
+ DPRINTF(Resource, "[tid:%i]: Misprediction detected at "
+ "[sn:%i] PC %#x,\n\t squashing after delay slot "
+ "instruction [sn:%i].\n",
+ tid, seq_num, inst->PC, inst->bdelaySeqNum);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch "
+ "misprediction at %#x\n", tid, inst->PC);
+ inst->setPredTarg(inst->nextNPC);
+ }
+
+ DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid,
+ inst->readPredTarg());
+
+ } else if(inst->isIndirectCtrl()){
+ inst->setPredTarg(inst->nextNPC);
+ inst->bdelaySeqNum = seq_num + 1;
+ DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid,
+ inst->readPredTarg());
+ } else {
+ panic("Non-control instruction (%s) mispredicting?!!",
+ inst->staticInst->getName());
+ }
+
+ DPRINTF(Resource, "[tid:%i] Squashing will start from stage %i.\n",
+ tid, stage_num);
+
+ cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
+
+ inst->squashingStage = stage_num;
+
+ // Squash throughout other resources
+ cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll,
+ inst, 0, 0, tid);
+
+ if (inst->predTaken()) {
+ predictedTakenIncorrect++;
+ } else {
+ predictedNotTakenIncorrect++;
+ }
+ }
+ exec_req->done();
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ }
+ } else {
+ // Regular ALU instruction
+ fault = inst->execute();
+
+ if (fault == NoFault) {
+ inst->setExecuted();
+ exec_req->done();
+
+ DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
+ inst->readTid(), inst->readIntResult(0));
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ cpu->trap(fault, tid);
+ }
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+
diff --git a/src/cpu/inorder/resources/execution_unit.hh b/src/cpu/inorder/resources/execution_unit.hh
new file mode 100644
index 000000000..e969497a2
--- /dev/null
+++ b/src/cpu/inorder/resources/execution_unit.hh
@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_EXECUTION_UNIT_HH__
+#define __CPU_INORDER_EXECUTION_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+
+class ExecutionUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ ExecuteInst
+ };
+
+ public:
+ ExecutionUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~ExecutionUnit() {}
+
+ public:
+ virtual void regStats();
+
+ /** Execute the function of this resource. The Default is action
+ * is to do nothing. More specific models will derive from this
+ * class and define their own execute function.
+ */
+ virtual void execute(int slot_num);
+
+ protected:
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ Stats::Scalar<> predictedTakenIncorrect;
+ Stats::Scalar<> predictedNotTakenIncorrect;
+};
+
+
+#endif //__CPU_INORDER_EXCUTION_UNIT_HH__
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc
new file mode 100644
index 000000000..00f76f74b
--- /dev/null
+++ b/src/cpu/inorder/resources/fetch_seq_unit.cc
@@ -0,0 +1,324 @@
+/*
+ * 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 "cpu/inorder/resources/fetch_seq_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{
+ instSize = sizeof(MachInst);
+
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ pcValid[tid] = false;
+ pcBlockStage[tid] = 0;
+
+ squashSeqNum[tid] = (InstSeqNum)-1;
+ lastSquashCycle[tid] = 0;
+ }
+}
+
+void
+FetchSeqUnit::init()
+{
+ resourceEvent = new FetchSeqEvent[width];
+
+ initSlots();
+}
+
+void
+FetchSeqUnit::execute(int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ ResourceRequest* fs_req = reqMap[slot_num];
+ DynInstPtr inst = fs_req->inst;
+ int tid = inst->readTid();
+ int stage_num = fs_req->getStageNum();
+ int seq_num = inst->seqNum;
+
+ fs_req->fault = NoFault;
+
+ switch (fs_req->cmd)
+ {
+ case AssignNextPC:
+ {
+ if (pcValid[tid]) {
+
+ if (delaySlotInfo[tid].targetReady &&
+ delaySlotInfo[tid].numInsts == 0) {
+ // Set PC to target
+ PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC
+ nextPC[tid] = PC[tid] + instSize; //next_NPC
+ nextNPC[tid] = PC[tid] + (2 * instSize);
+
+ delaySlotInfo[tid].targetReady = false;
+
+ DPRINTF(Resource, "[tid:%i]: Setting PC to delay slot target\n",tid);
+ }
+
+ inst->setPC(PC[tid]);
+ inst->setNextPC(PC[tid] + instSize);
+ inst->setNextNPC(PC[tid] + (instSize * 2));
+
+ inst->setPredTarg(inst->readNextNPC());
+
+ inst->setMemAddr(PC[tid]);
+ inst->setSeqNum(cpu->getAndIncrementInstSeq(tid));
+
+ DPRINTF(Resource, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid,
+ inst->seqNum, inst->readPC());
+
+ if (delaySlotInfo[tid].numInsts > 0) {
+ --delaySlotInfo[tid].numInsts;
+
+ // It's OK to set PC to target of branch
+ if (delaySlotInfo[tid].numInsts == 0) {
+ delaySlotInfo[tid].targetReady = true;
+ }
+
+ DPRINTF(Resource, "[tid:%i]: %i delay slot inst(s) left to"
+ " process.\n", tid, delaySlotInfo[tid].numInsts);
+ }
+
+ PC[tid] = nextPC[tid];
+ nextPC[tid] = nextNPC[tid];
+ nextNPC[tid] += instSize;
+
+ fs_req->done();
+ } else {
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid);
+ fs_req->setCompleted(false);
+ }
+ }
+ break;
+
+ case UpdateTargetPC:
+ {
+ if (inst->isControl()) {
+ // If it's a return, then we must wait for resolved address.
+ if (inst->isReturn() && !inst->predTaken()) {
+ cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true;
+ pcValid[tid] = false;
+ pcBlockStage[tid] = stage_num;
+ } else if (inst->isCondDelaySlot() && !inst->predTaken()) {
+ // Not-Taken AND Conditional Control
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. "
+ "Delay inst. Skipping delay slot and Updating PC to %08p\n",
+ tid, inst->seqNum, inst->readPC(), inst->readPredTarg());
+
+ DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
+ tid, stage_num, seq_num);
+
+ inst->bdelaySeqNum = seq_num;
+ inst->squashingStage = stage_num;
+
+ squashAfterInst(inst, stage_num, tid);
+ } else if (!inst->isCondDelaySlot() && !inst->predTaken()) {
+ // Not-Taken Control
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control "
+ "inst. updating PC to %08p\n", tid, inst->seqNum,
+ inst->readNextPC());
+
+ ++delaySlotInfo[tid].numInsts;
+ delaySlotInfo[tid].targetReady = false;
+ delaySlotInfo[tid].targetAddr = inst->readNextNPC();
+
+ } else if (inst->predTaken()) {
+ // Taken Control
+ ++delaySlotInfo[tid].numInsts;
+ delaySlotInfo[tid].targetReady = false;
+ delaySlotInfo[tid].targetAddr = inst->readPredTarg();
+
+ DPRINTF(Resource, "[tid:%i]: [sn:%i] Updating delay slot target "
+ "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg());
+
+ // Set-Up Squash Through-Out Pipeline
+ DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
+ tid, stage_num, seq_num + 1);
+ inst->bdelaySeqNum = seq_num + 1;
+ inst->squashingStage = stage_num;
+
+ // Do Squashing
+ squashAfterInst(inst, stage_num, tid);
+ }
+ } else {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Ignoring branch target update "
+ "since then is not a control instruction.\n", tid, inst->seqNum);
+ }
+
+ fs_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+inline void
+FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid)
+{
+ // Squash In Pipeline Stage
+ cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
+
+ // Squash inside current resource, so if there needs to be fetching on same cycle
+ // the fetch information will be correct.
+ // squash(inst, stage_num, inst->bdelaySeqNum, tid);
+
+ // Schedule Squash Through-out Resource Pool
+ cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
+}
+void
+FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i.\n",
+ tid, squash_stage);
+
+ InstSeqNum done_seq_num = inst->bdelaySeqNum;
+ Addr new_PC = inst->readPredTarg();
+
+ if (squashSeqNum[tid] <= done_seq_num &&
+ lastSquashCycle[tid] == curTick) {
+ DPRINTF(Resource, "[tid:%i]: Ignoring squash from stage %i, since"
+ "there is an outstanding squash that is older.\n",
+ tid, squash_stage);
+ } else {
+ squashSeqNum[tid] = done_seq_num;
+ lastSquashCycle[tid] = curTick;
+
+ // If The very next instruction number is the done seq. num,
+ // then we haven't seen the delay slot yet ... if it isn't
+ // the last done_seq_num then this is the delay slot inst.
+ if (cpu->nextInstSeqNum(tid) != done_seq_num &&
+ !inst->procDelaySlotOnMispred) {
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ // Reset PC
+ PC[tid] = new_PC;
+ nextPC[tid] = new_PC + instSize;
+ nextNPC[tid] = new_PC + (2 * instSize);
+
+ DPRINTF(Resource, "[tid:%i]: Setting PC to %08p.\n",
+ tid, PC[tid]);
+ } else {
+ delaySlotInfo[tid].numInsts = 1;
+ delaySlotInfo[tid].targetReady = false;
+ delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ? inst->branchTarget() : new_PC;
+
+ // Reset PC to Delay Slot Instruction
+ if (inst->procDelaySlotOnMispred) {
+ PC[tid] = new_PC;
+ nextPC[tid] = new_PC + instSize;
+ nextNPC[tid] = new_PC + (2 * instSize);
+ }
+
+ }
+
+ // Unblock Any Stages Waiting for this information to be updated ...
+ if (!pcValid[tid]) {
+ cpu->pipelineStage[pcBlockStage[tid]]->toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
+ }
+
+ pcValid[tid] = true;
+ }
+
+ Resource::squash(inst, squash_stage, squash_seq_num, tid);
+}
+
+FetchSeqUnit::FetchSeqEvent::FetchSeqEvent()
+ : ResourceEvent()
+{ }
+
+void
+FetchSeqUnit::FetchSeqEvent::process()
+{
+ FetchSeqUnit* fs_res = dynamic_cast<FetchSeqUnit*>(resource);
+ assert(fs_res);
+
+ for (int i=0; i < MaxThreads; i++) {
+ fs_res->PC[i] = fs_res->cpu->readPC(i);
+ fs_res->nextPC[i] = fs_res->cpu->readNextPC(i);
+ fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i);
+ DPRINTF(Resource, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n",
+ fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]);
+
+ fs_res->pcValid[i] = true;
+ }
+
+ //cpu->fetchPriorityList.push_back(tid);
+}
+
+
+void
+FetchSeqUnit::activateThread(unsigned tid)
+{
+ pcValid[tid] = true;
+
+ PC[tid] = cpu->readPC(tid);
+ nextPC[tid] = cpu->readNextPC(tid);
+ nextNPC[tid] = cpu->readNextNPC(tid);
+
+ cpu->fetchPriorityList.push_back(tid);
+
+ DPRINTF(Resource, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n",
+ tid, PC[tid], nextPC[tid], nextNPC[tid]);
+}
+
+void
+FetchSeqUnit::deactivateThread(unsigned tid)
+{
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ pcValid[tid] = false;
+ pcBlockStage[tid] = 0;
+
+ squashSeqNum[tid] = (InstSeqNum)-1;
+ lastSquashCycle[tid] = 0;
+
+ std::list<unsigned>::iterator thread_it = find(cpu->fetchPriorityList.begin(),
+ cpu->fetchPriorityList.end(),
+ tid);
+
+ if (thread_it != cpu->fetchPriorityList.end())
+ cpu->fetchPriorityList.erase(thread_it);
+}
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh
new file mode 100644
index 000000000..2b074bbaa
--- /dev/null
+++ b/src/cpu/inorder/resources/fetch_seq_unit.hh
@@ -0,0 +1,119 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_FETCH_SEQ_UNIT_HH__
+#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace ThePipeline;
+
+class FetchSeqUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ AssignNextPC,
+ UpdateTargetPC
+ };
+
+ public:
+ FetchSeqUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~FetchSeqUnit() {}
+
+ virtual void init();
+ virtual void activateThread(unsigned tid);
+ virtual void deactivateThread(unsigned tid);
+ virtual void execute(int slot_num);
+
+ /** Override default Resource squash sequence. This actually,
+ * looks in the global communication buffer to get squash
+ * info
+ */
+ virtual void squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid);
+
+
+ inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid);
+
+ protected:
+ unsigned instSize;
+
+ bool pcValid[ThePipeline::MaxThreads];
+ int pcBlockStage[ThePipeline::MaxThreads];
+
+ TheISA::IntReg PC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextPC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
+
+ /** Tracks delay slot information for threads in ISAs which use
+ * delay slots;
+ */
+ struct DelaySlotInfo {
+ InstSeqNum delaySlotSeqNum;
+ InstSeqNum branchSeqNum;
+ int numInsts;
+ Addr targetAddr;
+ bool targetReady;
+ };
+
+ DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads];
+
+ /** Squash Seq. Nums*/
+ InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
+
+ /** Squash Seq. Nums*/
+ Tick lastSquashCycle[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+
+ public:
+ class FetchSeqEvent : public ResourceEvent {
+ public:
+ /** Constructs a resource event. */
+ FetchSeqEvent();
+ virtual ~FetchSeqEvent() {}
+
+ /** Processes a resource event. */
+ virtual void process();
+ };
+
+};
+
+#endif
diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc
new file mode 100644
index 000000000..f4bbf3f5d
--- /dev/null
+++ b/src/cpu/inorder/resources/graduation_unit.cc
@@ -0,0 +1,113 @@
+/*
+ * 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 "cpu/inorder/resources/graduation_unit.hh"
+
+using namespace ThePipeline;
+
+GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{
+ lastCycleGrad = 0;
+ numCycleGrad = 0;
+
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
+ nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
+ }
+}
+
+void
+GraduationUnit::execute(int slot_num)
+{
+ ResourceRequest* grad_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid, seq_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ int stage_num = inst->resSched.top()->stageNum;
+
+ grad_req->fault = NoFault;
+
+ switch (grad_req->cmd)
+ {
+ case GraduateInst:
+ {
+ // @TODO: Instructions should never really get to this point since this should be handled
+ // through the request interface. Check to make sure this happens and delete this
+ // code.
+ if (lastCycleGrad != curTick) {
+ lastCycleGrad = curTick;
+ numCycleGrad = 0;
+ } else if (numCycleGrad > width) {
+ DPRINTF(Resource, "Graduation bandwidth reached for this cycle.\n");
+ return;
+ }
+
+ // Make sure this is the last thing on the resource schedule
+ assert(inst->resSched.size() == 1);
+
+ DPRINTF(Resource, "[tid:%i] Graduating instruction [sn:%i].\n",
+ tid, seq_num);
+
+ DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/);
+
+ // Release Non-Speculative "Block" on instructions that could not execute
+ // because there was a non-speculative inst. active.
+ // @TODO: Fix this functionality. Probably too conservative.
+ if (inst->isNonSpeculative()) {
+ *nonSpecInstActive[tid] = false;
+ DPRINTF(Resource, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n",
+ tid, seq_num);
+ }
+
+ if (inst->traceData) {
+ inst->traceData->setStageCycle(stage_num, curTick);
+ }
+
+ // Tell CPU that instruction is finished processing
+ cpu->instDone(inst, tid);
+
+ //cpu->pipelineStage[stage_num]->toPrevStages->
+ //stageInfo[stage_num][tid].doneSeqNum = inst->seqNum;
+
+ grad_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+}
diff --git a/src/cpu/inorder/resources/graduation_unit.hh b/src/cpu/inorder/resources/graduation_unit.hh
new file mode 100644
index 000000000..ad222b119
--- /dev/null
+++ b/src/cpu/inorder/resources/graduation_unit.hh
@@ -0,0 +1,70 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_GRAD_UNIT_HH__
+#define __CPU_INORDER_GRAD_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class GraduationUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ GraduateInst
+ };
+
+ public:
+ GraduationUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~GraduationUnit() {}
+
+ virtual void execute(int slot_num);
+
+ protected:
+ Tick lastCycleGrad;
+ int numCycleGrad;
+
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
+
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+};
+
+#endif //__CPU_INORDER_GRAD_UNIT_HH__
diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc
new file mode 100644
index 000000000..97924d2d3
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer.cc
@@ -0,0 +1,222 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+InstBuffer::regStats()
+{
+ instsBypassed
+ .name(name() + ".instsBypassed")
+ .desc("Number of Instructions Bypassed.");
+
+ Resource::regStats();
+}
+
+void
+InstBuffer::execute(int slot_idx)
+{
+ ResReqPtr ib_req = reqMap[slot_idx];
+ DynInstPtr inst = ib_req->inst;
+ int tid, seq_num, stage_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ stage_num = ib_req->getStageNum();
+ ib_req->fault = NoFault;
+
+ switch (ib_req->cmd)
+ {
+ case ScheduleOrBypass:
+ {
+ int next_stage = stage_num + 1;
+ int bypass_stage = stage_num + 2;
+ bool do_bypass = true;
+
+ if (!instList.empty()) {
+ DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n",
+ inst->seqNum, next_stage);
+ do_bypass = false;
+ } else if(cpu->pipelineStage[bypass_stage]->isBlocked(tid)) {
+ DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n",
+ inst->seqNum, next_stage);
+ do_bypass = false;
+ } else if(cpu->pipelineStage[bypass_stage]->stageBufferAvail() <= 0) {
+ DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because there is no room in "
+ "stage %i incoming stage buffer.\n", inst->seqNum, next_stage);
+ do_bypass = false;
+ }
+
+ if (!do_bypass) { // SCHEDULE USAGE OF BUFFER
+ DPRINTF(Resource, "Scheduling [sn:%i] for buffer insertion in stage %i\n",
+ inst->seqNum, next_stage);
+
+ // Add to schedule: Insert into buffer in next stage
+ int stage_pri = ThePipeline::getNextPriority(inst, next_stage);
+
+ inst->resSched.push(new ScheduleEntry(next_stage, stage_pri, id,
+ InstBuffer::InsertInst));
+
+ // Add to schedule: Remove from buffer in next next (bypass) stage
+ stage_pri = ThePipeline::getNextPriority(inst, bypass_stage);
+
+ inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id,
+ InstBuffer::RemoveInst));
+ } else { // BYPASS BUFFER & NEXT STAGE
+ DPRINTF(Resource, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n",
+ inst->seqNum, next_stage, bypass_stage);
+ inst->setNextStage(bypass_stage);
+ instsBypassed++;
+ }
+
+ ib_req->done();
+ }
+ break;
+
+ case InsertInst:
+ {
+ bool inserted = false;
+
+ if (instList.size() < width) {
+ DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
+ tid, seq_num);
+ insert(inst);
+ inserted = true;
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Denying [sn:%i] request because "
+ "buffer is full.\n", tid, seq_num);
+
+
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ DPRINTF(Resource,"Serving [tid:%i] [sn:%i].\n", (*list_it)->readTid(), (*list_it)->seqNum);
+ list_it++;
+ }
+ }
+
+ ib_req->done(inserted);
+ }
+ break;
+
+ case RemoveInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n",
+ tid, seq_num);
+ remove(inst);
+ ib_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+ DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size());
+}
+
+void
+InstBuffer::insert(DynInstPtr inst)
+{
+ instList.push_back(inst);
+}
+
+void
+InstBuffer::remove(DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ if((*list_it) == inst) {
+ instList.erase(list_it);
+ break;
+ }
+ list_it++;
+ }
+}
+
+void
+InstBuffer::pop(unsigned tid)
+{
+ instList.pop_front();
+}
+
+ThePipeline::DynInstPtr
+InstBuffer::top(unsigned tid)
+{
+ return instList.front();
+}
+
+void
+InstBuffer::squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ queue<list<DynInstPtr>::iterator> remove_list;
+ list<DynInstPtr>::iterator list_it = instList.begin();
+ list<DynInstPtr>::iterator list_end = instList.end();
+
+ // Collect All Instructions to be Removed in Remove List
+ while (list_it != list_end) {
+ if((*list_it)->readTid() == tid &&
+ (*list_it)->seqNum > squash_seq_num) {
+ (*list_it)->setSquashed();
+ remove_list.push(list_it);
+ }
+
+ list_it++;
+ }
+
+ // Removed Instructions from InstList & Clear Remove List
+ while (!remove_list.empty()) {
+ DPRINTF(Resource, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n",
+ tid, (*remove_list.front())->seqNum);
+ instList.erase(remove_list.front());
+ remove_list.pop();
+ }
+
+ Resource::squash(inst, stage_num, squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh
new file mode 100644
index 000000000..f4851e868
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer.hh
@@ -0,0 +1,93 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
+#define __CPU_INORDER_INST_BUFF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class InstBuffer : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ InsertInst,
+ InsertAddr,
+ RemoveInst,
+ RemoveAddr,
+ ScheduleOrBypass
+ };
+
+ public:
+ InstBuffer(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~InstBuffer() {}
+
+ virtual void regStats();
+
+ virtual void execute(int slot_num);
+
+ virtual void insert(DynInstPtr inst);
+
+ virtual void remove(DynInstPtr inst);
+
+ virtual void pop(unsigned tid);
+
+ virtual DynInstPtr top(unsigned tid);
+
+ virtual void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ public:
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar<> instsBypassed;
+
+};
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc
new file mode 100644
index 000000000..7e2c98837
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer_new.cc
@@ -0,0 +1,156 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+ResReqPtr
+InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top());
+ assert(ib_entry);
+
+ return new InstBufferRequest(this, inst, stage_num, id, slot_num,
+ ib_entry->cmd);
+}
+
+void
+InstBuffer::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]);
+ assert(ib_req);
+
+ DynInstPtr inst = ib_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ ib_req->fault = NoFault;
+
+ switch (ib_req->cmd)
+ {
+ case InsertInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
+ tid, seq_num);
+ insert(inst);
+ ib_req->done();
+ }
+ break;
+
+ case RemoveInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n",
+ tid, seq_num);
+ remove(inst);
+ ib_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+ DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size());
+}
+
+void
+InstBuffer::insert(DynInstPtr inst)
+{
+ instList.push_back(inst);
+}
+
+void
+InstBuffer::remove(DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ if((*list_it) == inst) {
+ instList.erase(list_it);
+ break;
+ }
+ list_it++;
+ }
+}
+
+void
+InstBuffer::pop()
+{ instList.pop_front(); }
+
+ThePipeline::DynInstPtr
+InstBuffer::top()
+{ return instList.front(); }
+
+void
+InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+ list<DynInstPtr>::iterator list_it = instList.begin();
+ list<DynInstPtr>::iterator list_end = instList.end();
+ queue<list<DynInstPtr>::iterator> remove_list;
+
+ // Collect All Instructions to be Removed in Remove List
+ while (list_it != list_end) {
+ if((*list_it)->seqNum > squash_seq_num) {
+ DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n",
+ tid, (*list_it)->seqNum);
+ (*list_it)->setSquashed();
+ remove_list.push(list_it);
+ }
+
+ list_it++;
+ }
+
+ // Removed Instructions from InstList & Clear Remove List
+ while (!remove_list.empty()) {
+ instList.erase(remove_list.front());
+ remove_list.pop();
+ }
+
+ Resource::squash(squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh
new file mode 100644
index 000000000..e374fa109
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer_new.hh
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
+#define __CPU_INORDER_INST_BUFF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class InstBuffer : public Resource {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ InsertInst,
+ InsertAddr,
+ RemoveInst,
+ RemoveAddr
+ };
+
+ public:
+ InstBuffer(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu);
+ virtual ~InstBuffer() {}
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num);
+
+ virtual void execute(int slot_num);
+
+ virtual void insert(DynInstPtr inst);
+
+ virtual void remove(DynInstPtr inst);
+
+ virtual void pop();
+
+ virtual DynInstPtr top();
+
+ virtual void squash(InstSeqNum squash_seq_num, unsigned tid);
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ /** @todo: Add Resource Stats Here */
+
+};
+
+struct InstBufferEntry : public ThePipeline::ScheduleEntry {
+ InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) :
+ ScheduleEntry(stage_num, res_num), cmd(_cmd)
+ { }
+
+ InstBuffer::Command cmd;
+};
+
+class InstBufferRequest : public ResourceRequest {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
+ InstBuffer::Command _cmd)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num),
+ cmd(_cmd)
+ { }
+
+ InstBuffer::Command cmd;
+};
+
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/mem_dep_unit.hh b/src/cpu/inorder/resources/mem_dep_unit.hh
new file mode 100644
index 000000000..0bd850c5c
--- /dev/null
+++ b/src/cpu/inorder/resources/mem_dep_unit.hh
@@ -0,0 +1,66 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_GRAD_UNIT_HH__
+#define __CPU_INORDER_GRAD_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class MemDepUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ MemDepUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu);
+ virtual ~MemDepUnit() {}
+
+ virtual void execute(int slot_num);
+
+ protected:
+ Tick lastCycleGrad;
+ int numCycleGrad;
+
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
+
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+};
+
+#endif //__CPU_INORDER_GRAD_UNIT_HH__
diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc
new file mode 100644
index 000000000..abef11247
--- /dev/null
+++ b/src/cpu/inorder/resources/mult_div_unit.cc
@@ -0,0 +1,291 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "cpu/inorder/resources/mult_div_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/op_class.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{
+ multRepeatRate = params->multRepeatRate;
+ multLatency = params->multLatency;
+
+ div8RepeatRate = params->div8RepeatRate;
+ div8Latency = params->div8Latency;
+
+ div16RepeatRate = params->div16RepeatRate;
+ div16Latency = params->div16Latency;
+
+ div24RepeatRate = params->div24RepeatRate;
+ div24Latency = params->div24Latency;
+
+ div32RepeatRate = params->div32RepeatRate;
+ div32Latency = params->div32Latency;
+}
+
+void
+MultDivUnit::regStats()
+{
+ multInstReqsProcessed
+ .name(name() + ".multInstReqsProcessed")
+ .desc("Number of Multiply Requests Processed.");
+
+ divInstReqsProcessed
+ .name(name() + ".divInstReqsProcessed")
+ .desc("Number of Divide Requests Processed.");
+
+ Resource::regStats();
+}
+
+void
+MultDivUnit::init()
+{
+ // Set Up Resource Events to Appropriate Resource BandWidth
+ resourceEvent = new MDUEvent[width];
+
+ initSlots();
+}
+
+int
+MultDivUnit::findSlot(DynInstPtr inst)
+{
+ DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
+ inst->seqNum, slotsAvail(), slotsInUse());
+
+ return Resource::findSlot(inst);
+}
+
+void
+MultDivUnit::freeSlot(int slot_idx)
+{
+ DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
+ reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse());
+
+ Resource::freeSlot(slot_idx);
+}
+
+
+int
+MultDivUnit::getSlot(DynInstPtr inst)
+{
+ // If MDU already has instruction, return current slot.
+ int slot_num = findSlot(inst);
+
+ // If we have this instruction's request already then return
+ if (slot_num != -1 &&
+ inst->resSched.top()->cmd == reqMap[slot_num]->cmd)
+ return slot_num;
+
+ unsigned repeat_rate = 0;
+
+ /** Enforce MDU dependencies after a multiply is seen last */
+ if (lastOpType == IntMultOp) {
+ repeat_rate = multRepeatRate;
+ }
+
+ /** Enforce dependencies after a divide is seen last */
+ if (lastOpType == IntDivOp) {
+ switch (lastDivSize) {
+ case 8:
+ repeat_rate = div8RepeatRate;
+ break;
+
+ case 16:
+ repeat_rate = div16RepeatRate;
+ break;
+
+ case 24:
+ repeat_rate = div24RepeatRate;
+ break;
+
+ case 32:
+ repeat_rate = div32RepeatRate;
+ break;
+ }
+ }
+
+ if (lastMDUCycle + repeat_rate > curTick) {
+ DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n",
+ lastMDUCycle + repeat_rate);
+ return -1;
+ } else {
+ int rval = Resource::getSlot(inst);
+ DPRINTF(InOrderMDU, "MDU request should pass: %i.\n",
+ rval);
+
+ if (rval != -1) {
+ }
+
+ return rval;
+ }
+}
+
+int
+MultDivUnit::getDivOpSize(DynInstPtr inst)
+{
+ // Get RT Register from instruction (index #1)
+ uint32_t div_op = inst->readIntSrc(1);
+
+ if (div_op <= 0xFF) {
+ return 8;
+ } else if (div_op <= 0xFFFF) {
+ return 16;
+ } else if (div_op <= 0xFFFFFF) {
+ return 24;
+ } else {
+ return 32;
+ }
+}
+
+void
+MultDivUnit::execute(int slot_num)
+{
+ ResourceRequest* mult_div_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+
+ //int tid = inst->readTid();
+ //int seq_num = inst->seqNum;
+
+ switch (mult_div_req->cmd)
+ {
+ case StartMultDiv:
+ DPRINTF(InOrderMDU, "Start MDU called ...\n");
+
+ if (inst->opClass() == IntMultOp) {
+ scheduleEvent(slot_num, multLatency);
+ multInstReqsProcessed++;
+ } else if (inst->opClass() == IntDivOp) {
+ int op_size = getDivOpSize(inst);
+
+ switch (op_size)
+ {
+ case 8:
+ scheduleEvent(slot_num, div8Latency);
+ break;
+
+ case 16:
+ scheduleEvent(slot_num, div16Latency);
+ break;
+
+ case 24:
+ scheduleEvent(slot_num, div24Latency);
+ break;
+
+ case 32:
+ scheduleEvent(slot_num, div32Latency);
+ break;
+ }
+
+ lastDivSize = op_size;
+
+ divInstReqsProcessed++;
+ }
+
+ // Allow to pass through to next stage while
+ // event processes
+ mult_div_req->setCompleted();
+ break;
+
+ case MultDiv:
+ DPRINTF(InOrderMDU, "Execute MDU called ...\n");
+ exeMulDiv(slot_num);
+ mult_div_req->done();
+ break;
+
+
+ case EndMultDiv:
+ //@TODO: Why not allow high-latency requests to sleep
+ // within stage until event wakes up????
+ // Seems wasteful to continually check to see if
+ // this is done when we have a event in parallel
+ // counting down the time
+ {
+ DPRINTF(InOrderMDU, "End MDU called ...\n");
+ if (mult_div_req->getInst()->isExecuted())
+ mult_div_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+void
+MultDivUnit::exeMulDiv(int slot_num)
+{
+ ResourceRequest* mult_div_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+
+ fault = inst->execute();
+
+ if (fault == NoFault) {
+ inst->setExecuted();
+ mult_div_req->setCompleted();
+
+ DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
+ inst->readTid(), inst->readIntResult(0));
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ cpu->trap(fault, tid);
+ }
+}
+
+
+MDUEvent::MDUEvent()
+ : ResourceEvent()
+{ }
+
+void
+MDUEvent::process()
+{
+ MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
+
+ mdu_res->exeMulDiv(slotIdx);
+
+ ResourceRequest* mult_div_req = resource->reqMap[slotIdx];
+
+ mult_div_req->done();
+}
+
+
diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh
new file mode 100644
index 000000000..762442c4b
--- /dev/null
+++ b/src/cpu/inorder/resources/mult_div_unit.hh
@@ -0,0 +1,138 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_MULT_DIV_UNIT_HH__
+#define __CPU_INORDER_MULT_DIV_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/op_class.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+
+class MDUEvent;
+
+class MultDivUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ StartMultDiv,
+ EndMultDiv,
+ MultDiv
+ };
+
+ public:
+ MultDivUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~MultDivUnit() {}
+
+ public:
+ /** Override default Resource getSlot(). Will only getSlot if
+ * valid mult/div sequence is being maintained
+ */
+ virtual int getSlot(DynInstPtr inst);
+
+ virtual int findSlot(DynInstPtr inst);
+
+ virtual void freeSlot(int slot_idx);
+
+ virtual void init();
+
+ /** Get Operand Size For A Division Operation */
+ int getDivOpSize(DynInstPtr inst);
+
+ /** Override default Resource execute */
+ virtual void execute(int slot_num);
+
+ void exeMulDiv(int slot_num);
+
+ /** Register extra resource stats */
+ virtual void regStats();
+
+ protected:
+ /** Latency & Repeat Rate for Multiply Insts */
+ unsigned multLatency;
+ unsigned multRepeatRate;
+
+ /** Latency & Repeat Rate for 8-bit Divide Insts */
+ unsigned div8Latency;
+ unsigned div8RepeatRate;
+
+ /** Latency & Repeat Rate for 16-bit Divide Insts */
+ unsigned div16Latency;
+ unsigned div16RepeatRate;
+
+ /** Latency & Repeat Rate for 24-bit Divide Insts */
+ unsigned div24Latency;
+ unsigned div24RepeatRate;
+
+ /** Latency & Repeat Rate for 32-bit Divide Insts */
+ unsigned div32Latency;
+ unsigned div32RepeatRate;
+
+ /** Last cycle that MDU was used */
+ Tick lastMDUCycle;
+
+ /** Last type of instruction MDU started processing */
+ OpClass lastOpType;
+
+ /** Last Division Operand of instruction MDU was processing */
+ uint32_t lastDivSize;
+
+ /** Last instruction name the MDU used */
+ std::string lastInstName;
+
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar<> multInstReqsProcessed;
+
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar<> divInstReqsProcessed;
+
+ MDUEvent *mduEvent;
+};
+
+class MDUEvent : public ResourceEvent
+{
+ public:
+ MDUEvent();
+ virtual ~MDUEvent() { }
+
+
+ virtual void process();
+};
+
+
+#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__
diff --git a/src/cpu/inorder/resources/resource_list.hh b/src/cpu/inorder/resources/resource_list.hh
new file mode 100644
index 000000000..cbe2ad8c3
--- /dev/null
+++ b/src/cpu/inorder/resources/resource_list.hh
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef CPU_INORDER_RESOURCE_LIST_HH
+#define CPU_INORDER_RESOURCE_LIST_HH
+
+#include "cpu/inorder/resources/cache_unit.hh"
+#include "cpu/inorder/resources/execution_unit.hh"
+#include "cpu/inorder/resources/use_def.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/resources/decode_unit.hh"
+#include "cpu/inorder/resources/graduation_unit.hh"
+#include "cpu/inorder/resources/tlb_unit.hh"
+#include "cpu/inorder/resources/fetch_seq_unit.hh"
+#include "cpu/inorder/resources/branch_predictor.hh"
+#include "cpu/inorder/resources/agen_unit.hh"
+#include "cpu/inorder/resources/mult_div_unit.hh"
+
+#endif
diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc
new file mode 100644
index 000000000..9b0decedb
--- /dev/null
+++ b/src/cpu/inorder/resources/tlb_unit.cc
@@ -0,0 +1,186 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/tlb_unit.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+TLBUnit::TLBUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : InstBuffer(res_name, res_id, res_width, res_latency, _cpu, params)
+{
+ for (int i=0; i < MaxThreads; i++) {
+ tlbBlocked[i] = false;
+ }
+}
+
+void
+TLBUnit::init()
+{
+ resourceEvent = new TLBUnitEvent[width];
+
+ initSlots();
+}
+
+int
+TLBUnit::getSlot(DynInstPtr inst)
+{
+ if (tlbBlocked[inst->threadNumber]) {
+ return -1;
+ } else {
+ return Resource::getSlot(inst);
+ }
+}
+
+ResourceRequest*
+TLBUnit::getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd)
+{
+ return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num,
+ cmd);
+}
+
+void
+TLBUnit::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ TLBUnitRequest* tlb_req = dynamic_cast<TLBUnitRequest*>(reqMap[slot_idx]);
+ assert(tlb_req);
+
+ DynInstPtr inst = tlb_req->inst;
+ int tid, seq_num, stage_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ stage_num = tlb_req->getStageNum();
+
+ tlb_req->fault = NoFault;
+
+ switch (tlb_req->cmd)
+ {
+ case FetchLookup:
+ {
+ tlb_req->fault =
+ this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]);
+
+ if (tlb_req->fault != NoFault) {
+ DPRINTF(Resource, "[tid:%i]: %s encountered while translating "
+ "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
+ tlb_req->memReq->getVaddr(), seq_num);
+ //insert(inst);
+ cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
+ tlbBlocked[tid] = true;
+ scheduleEvent(slot_idx, 1);
+
+ // @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault
+ // Let CPU handle the fault
+ cpu->trap(tlb_req->fault, tid);
+ } else {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated "
+ "to phys. addr:%08p.\n", tid, seq_num,
+ tlb_req->memReq->getVaddr(),
+ tlb_req->memReq->getPaddr());
+ tlb_req->done();
+ }
+ }
+ break;
+
+ case DataLookup:
+ {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
+ tid, seq_num, tlb_req->memReq->getVaddr());
+
+ tlb_req->fault =
+ this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]);
+
+ if (tlb_req->fault != NoFault) {
+ DPRINTF(Resource, "[tid:%i]: %s encountered while translating "
+ "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
+ tlb_req->memReq->getVaddr(), seq_num);
+ //insert(inst);
+ cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
+ tlbBlocked[tid] = true;
+ scheduleEvent(slot_idx, 1);
+
+ // Let CPU handle the fault
+ cpu->trap(tlb_req->fault, tid);
+ } else {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated "
+ "to phys. addr:%08p.\n", tid, seq_num,
+ tlb_req->memReq->getVaddr(),
+ tlb_req->memReq->getPaddr());
+ tlb_req->done();
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+TLBUnitEvent::TLBUnitEvent()
+ : ResourceEvent()
+{ }
+
+void
+TLBUnitEvent::process()
+{
+ DynInstPtr inst = resource->reqMap[slotIdx]->inst;
+ int stage_num = resource->reqMap[slotIdx]->getStageNum();
+ int tid = inst->threadNumber;
+
+ DPRINTF(Resource, "Waking up from TLB Miss caused by [sn:%i].\n",
+ inst->seqNum);
+
+ TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource);
+ assert(tlb_res);
+
+ tlb_res->tlbBlocked[tid] = false;
+
+ tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid);
+
+ // Effectively NOP the instruction but still allow it
+ // to commit
+ //while (!inst->resSched.empty() &&
+ // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) {
+ //inst->resSched.pop();
+ //}
+}
diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh
new file mode 100644
index 000000000..c7fee6030
--- /dev/null
+++ b/src/cpu/inorder/resources/tlb_unit.hh
@@ -0,0 +1,124 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_TLB_UNIT_HH__
+#define __CPU_INORDER_TLB_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class TLBUnit : public InstBuffer {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum TLBCommand {
+ FetchLookup,
+ DataLookup
+ };
+
+ public:
+ TLBUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~TLBUnit() {}
+
+ void init();
+
+ int getSlot(DynInstPtr inst);
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ virtual void execute(int slot_num);
+
+ bool tlbBlocked[ThePipeline::MaxThreads];
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ /** @todo: Add Resource Stats Here */
+
+};
+
+class TLBUnitEvent : public ResourceEvent {
+ public:
+ /** Constructs a resource event. */
+ TLBUnitEvent();
+ virtual ~TLBUnitEvent() {}
+
+ /** Processes a resource event. */
+ virtual void process();
+};
+
+class TLBUnitRequest : public ResourceRequest {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
+ unsigned _cmd)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd)
+ {
+ Addr aligned_addr;
+ int req_size;
+ unsigned flags;
+
+ if (_cmd == TLBUnit::FetchLookup) {
+ aligned_addr = inst->getMemAddr();
+ req_size = sizeof(MachInst);
+ flags = 0;
+ } else {
+ aligned_addr = inst->getMemAddr();;
+ req_size = inst->getMemAccSize();
+ flags = inst->getMemFlags();
+ }
+
+ // @TODO: Add Vaddr & Paddr functions
+ inst->memReq = new Request(inst->readTid(), aligned_addr, req_size,
+ flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid());
+
+ memReq = inst->memReq;
+ }
+
+ RequestPtr memReq;
+};
+
+
+#endif //__CPU_INORDER_TLB_UNIT_HH__
diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc
new file mode 100644
index 000000000..ed697c4ca
--- /dev/null
+++ b/src/cpu/inorder/resources/use_def.cc
@@ -0,0 +1,326 @@
+/*
+ * 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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/use_def.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ maxSeqNum((InstSeqNum)-1)
+{
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
+ nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
+
+ outReadSeqNum[tid] = maxSeqNum;
+ outWriteSeqNum[tid] = maxSeqNum;
+
+ regDepMap[tid] = &cpu->archRegDepMap[tid];
+ }
+}
+
+ResReqPtr
+UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd)
+{
+ return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd,
+ inst->resSched.top()->idx);
+}
+
+
+ResReqPtr
+UseDefUnit::findRequest(DynInstPtr inst)
+{
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>((*map_it).second);
+ assert(ud_req);
+
+ if (ud_req &&
+ ud_req->getInst() == inst &&
+ ud_req->cmd == inst->resSched.top()->cmd &&
+ ud_req->useDefIdx == inst->resSched.top()->idx) {
+ return ud_req;
+ }
+ map_it++;
+ }
+
+ return NULL;
+}
+
+void
+UseDefUnit::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqMap[slot_idx]);
+ assert(ud_req);
+
+ DynInstPtr inst = ud_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ int ud_idx = ud_req->useDefIdx;
+
+ // If there is a non-speculative instruction
+ // in the pipeline then stall instructions here
+ if (*nonSpecInstActive[tid] == true &&
+ seq_num > *nonSpecSeqNum[tid]) {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i] cannot execute because there is "
+ "non-speculative instruction [sn:%i] has not graduated.\n",
+ tid, seq_num, *nonSpecSeqNum[tid]);
+ return;
+ } else if (inst->isNonSpeculative()) {
+ *nonSpecInstActive[tid] = true;
+ *nonSpecSeqNum[tid] = seq_num;
+ }
+
+ switch (ud_req->cmd)
+ {
+ case ReadSrcReg:
+ {
+ int reg_idx = inst->_srcRegIdx[ud_idx];
+
+ DPRINTF(Resource, "[tid:%i]: Attempting to read source register idx %i.\n",
+ tid, ud_idx);
+
+ // Ask register dependency map if it is OK to read from Arch. Reg. File
+ if (regDepMap[tid]->canRead(reg_idx, inst)) {
+ // Read From Register File
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(Resource, "[tid:%i]: Reading Int Reg %i from Register File.\n",
+ tid, reg_idx);
+ inst->setIntSrc(ud_idx,
+ cpu->readIntReg(reg_idx,inst->readTid()));
+ } else if (reg_idx <= Ctrl_Base_DepTag) {
+ reg_idx -= FP_Base_DepTag;
+ DPRINTF(Resource, "[tid:%i]: Reading Float Reg %i from Register File.\n",
+ tid, reg_idx);
+ inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now
+ cpu->readFloatRegBits(reg_idx, inst->readTid()));
+ } else {
+ reg_idx -= Ctrl_Base_DepTag;
+ DPRINTF(Resource, "[tid:%i]: Reading Misc Reg %i from Register File.\n",
+ tid, reg_idx);
+ inst->setIntSrc(ud_idx,
+ cpu->readMiscReg(reg_idx, inst->readTid()));
+ }
+
+ outReadSeqNum[tid] = maxSeqNum;
+
+ ud_req->done();
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's"
+ " registers yet.\n", tid, outReadSeqNum[tid]);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n",
+ tid, outReadSeqNum[tid]);
+ }
+
+ } else {
+ DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx, ud_idx, inst);
+
+ if (forward_inst) {
+
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx);
+
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from "
+ "[sn:%i] to [sn:%i] source #%i.\n",
+ tid, forward_inst->readIntResult(dest_reg_idx) ,
+ forward_inst->seqNum, inst->seqNum, ud_idx);
+ inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx));
+ } else if (reg_idx <= Ctrl_Base_DepTag) {
+ DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from "
+ "[sn:%i] to [sn:%i] source #%i.\n",
+ tid, forward_inst->readFloatResult(dest_reg_idx) ,
+ forward_inst->seqNum, inst->seqNum, ud_idx);
+ inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx));
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from "
+ "[sn:%i] to [sn:%i] source #%i.\n",
+ tid, forward_inst->readIntResult(dest_reg_idx) ,
+ forward_inst->seqNum, inst->seqNum, ud_idx);
+ inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx));
+ }
+
+ outReadSeqNum[tid] = maxSeqNum;
+
+ ud_req->done();
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's"
+ " registers yet.\n", tid, outReadSeqNum[tid]);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n",
+ tid, outReadSeqNum[tid]);
+ }
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Source register idx: %i is not ready to read.\n",
+ tid, reg_idx);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n",
+ tid, reg_idx);
+ outReadSeqNum[tid] = inst->seqNum;
+ }
+ }
+ }
+ break;
+
+ case WriteDestReg:
+ {
+ int reg_idx = inst->_destRegIdx[ud_idx];
+
+ if (regDepMap[tid]->canWrite(reg_idx, inst)) {
+ DPRINTF(Resource, "[tid:%i]: Attempting to write to Register File.\n",
+ tid);
+
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(Resource, "[tid:%i]: Writing 0x%x to register idx %i.\n",
+ tid, inst->readIntResult(ud_idx), reg_idx);
+
+ // Remove Dependencies
+ regDepMap[tid]->removeFront(reg_idx, inst);
+
+ cpu->setIntReg(reg_idx,
+ inst->readIntResult(ud_idx),
+ inst->readTid());
+ } else if(reg_idx <= Ctrl_Base_DepTag) {
+
+ // Remove Dependencies
+ regDepMap[tid]->removeFront(reg_idx, inst);
+
+ reg_idx -= FP_Base_DepTag;
+
+ cpu->setFloatReg(reg_idx, // Check for FloatRegBits Here
+ inst->readFloatResult(ud_idx),
+ inst->readTid());
+ } else {
+ // Remove Dependencies
+ regDepMap[tid]->removeFront(reg_idx, inst);
+
+ reg_idx -= Ctrl_Base_DepTag;
+ cpu->setMiscReg(reg_idx,
+ inst->readIntResult(ud_idx),
+ inst->readTid());
+ }
+
+ outWriteSeqNum[tid] = maxSeqNum;
+
+ ud_req->done();
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's"
+ " registers yet.\n", tid, outReadSeqNum);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n",
+ tid, outReadSeqNum);
+ }
+ } else {
+ DPRINTF(Resource, "[tid:%i]: Dest. register idx: %i is not ready to write.\n",
+ tid, reg_idx);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n",
+ tid, reg_idx);
+ outWriteSeqNum[tid] = inst->seqNum;
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+}
+
+void
+UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i]: Updating Due To Squash After [sn:%i].\n",
+ tid, squash_seq_num);
+
+ std::vector<int> slot_remove_list;
+
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ ResReqPtr req_ptr = (*map_it).second;
+
+ if (req_ptr &&
+ req_ptr->getInst()->readTid() == tid &&
+ req_ptr->getInst()->seqNum > squash_seq_num) {
+
+ DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
+ req_ptr->getInst()->readTid(),
+ req_ptr->getInst()->seqNum);
+
+ regDepMap[tid]->remove(req_ptr->getInst());
+
+ int req_slot_num = req_ptr->getSlot();
+
+ if (latency > 0)
+ unscheduleEvent(req_slot_num);
+
+ // Mark slot for removal from resource
+ slot_remove_list.push_back(req_ptr->getSlot());
+ }
+
+ map_it++;
+ }
+
+ // Now Delete Slot Entry from Req. Map
+ for (int i = 0; i < slot_remove_list.size(); i++) {
+ freeSlot(slot_remove_list[i]);
+ }
+
+ if (outReadSeqNum[tid] >= squash_seq_num) {
+ DPRINTF(Resource, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid);
+ outReadSeqNum[tid] = maxSeqNum;
+ } else if (outReadSeqNum[tid] != maxSeqNum) {
+ DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n",
+ tid, outReadSeqNum[tid]);
+ }
+
+ if (outWriteSeqNum[tid] >= squash_seq_num) {
+ DPRINTF(Resource, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid);
+ outWriteSeqNum[tid] = maxSeqNum;
+ } else if (outWriteSeqNum[tid] != maxSeqNum) {
+ DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n",
+ tid, outWriteSeqNum[tid]);
+ }
+}
diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh
new file mode 100644
index 000000000..238591117
--- /dev/null
+++ b/src/cpu/inorder/resources/use_def.hh
@@ -0,0 +1,102 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __CPU_INORDER_USE_DEF_UNIT_HH__
+#define __CPU_INORDER_USE_DEF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+
+class UseDefUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ ReadSrcReg,
+ WriteDestReg
+ };
+
+ public:
+ UseDefUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~UseDefUnit() {}
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ virtual ResReqPtr findRequest(DynInstPtr inst);
+
+ virtual void execute(int slot_num);
+
+ virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ const InstSeqNum maxSeqNum;
+
+ protected:
+ RegDepMap *regDepMap[ThePipeline::MaxThreads];
+
+ /** Outstanding Seq. Num. Trying to Read from Register File */
+ InstSeqNum outReadSeqNum[ThePipeline::MaxThreads];
+
+ InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads];
+
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
+
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+
+ public:
+ class UseDefRequest : public ResourceRequest {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd, int use_def_idx)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd),
+ useDefIdx(use_def_idx)
+ { }
+
+ int useDefIdx;
+ };
+};
+
+#endif //__CPU_INORDER_USE_DEF_UNIT_HH__