InOrder: Import new inorder CPU model from MIPS.
authorKorey Sewell <ksewell@umich.edu>
Tue, 10 Feb 2009 23:49:29 +0000 (15:49 -0800)
committerKorey Sewell <ksewell@umich.edu>
Tue, 10 Feb 2009 23:49:29 +0000 (15:49 -0800)
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!

64 files changed:
src/cpu/cpu_models.py
src/cpu/inorder/InOrderCPU.py [new file with mode: 0644]
src/cpu/inorder/InOrderTrace.py [new file with mode: 0644]
src/cpu/inorder/SConscript [new file with mode: 0644]
src/cpu/inorder/SConsopts [new file with mode: 0644]
src/cpu/inorder/comm.hh [new file with mode: 0644]
src/cpu/inorder/cpu.cc [new file with mode: 0644]
src/cpu/inorder/cpu.hh [new file with mode: 0644]
src/cpu/inorder/first_stage.cc [new file with mode: 0644]
src/cpu/inorder/first_stage.hh [new file with mode: 0644]
src/cpu/inorder/inorder_cpu_builder.cc [new file with mode: 0644]
src/cpu/inorder/inorder_dyn_inst.cc [new file with mode: 0644]
src/cpu/inorder/inorder_dyn_inst.hh [new file with mode: 0644]
src/cpu/inorder/inorder_trace.cc [new file with mode: 0644]
src/cpu/inorder/inorder_trace.hh [new file with mode: 0644]
src/cpu/inorder/params.hh [new file with mode: 0644]
src/cpu/inorder/pipeline_stage.cc [new file with mode: 0644]
src/cpu/inorder/pipeline_stage.hh [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.5stage.cc [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.5stage.hh [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.9stage.cc [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.9stage.hh [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.9stage.smt2.cc [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.9stage.smt2.hh [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.cc [new file with mode: 0644]
src/cpu/inorder/pipeline_traits.hh [new file with mode: 0644]
src/cpu/inorder/reg_dep_map.cc [new file with mode: 0644]
src/cpu/inorder/reg_dep_map.hh [new file with mode: 0644]
src/cpu/inorder/resource.cc [new file with mode: 0644]
src/cpu/inorder/resource.hh [new file with mode: 0644]
src/cpu/inorder/resource_pool.9stage.cc [new file with mode: 0644]
src/cpu/inorder/resource_pool.cc [new file with mode: 0644]
src/cpu/inorder/resource_pool.hh [new file with mode: 0644]
src/cpu/inorder/resources/agen_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/agen_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/bpred_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/bpred_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/branch_predictor.cc [new file with mode: 0644]
src/cpu/inorder/resources/branch_predictor.hh [new file with mode: 0644]
src/cpu/inorder/resources/cache_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/cache_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/decode_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/decode_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/execution_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/execution_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/fetch_seq_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/fetch_seq_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/graduation_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/graduation_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/inst_buffer.cc [new file with mode: 0644]
src/cpu/inorder/resources/inst_buffer.hh [new file with mode: 0644]
src/cpu/inorder/resources/inst_buffer_new.cc [new file with mode: 0644]
src/cpu/inorder/resources/inst_buffer_new.hh [new file with mode: 0644]
src/cpu/inorder/resources/mem_dep_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/mult_div_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/mult_div_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/resource_list.hh [new file with mode: 0644]
src/cpu/inorder/resources/tlb_unit.cc [new file with mode: 0644]
src/cpu/inorder/resources/tlb_unit.hh [new file with mode: 0644]
src/cpu/inorder/resources/use_def.cc [new file with mode: 0644]
src/cpu/inorder/resources/use_def.hh [new file with mode: 0644]
src/cpu/inorder/thread_context.cc [new file with mode: 0644]
src/cpu/inorder/thread_context.hh [new file with mode: 0644]
src/cpu/inorder/thread_state.hh [new file with mode: 0644]

index 5b0c6c4dac12140effd383fecba23ab830f7bb46..793f8c6460a3df4df55f2fec3d2fe4dcf9cc50e4 100644 (file)
@@ -82,3 +82,6 @@ CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
 CpuModel('O3CPU', 'o3_cpu_exec.cc',
          '#include "cpu/o3/isa_specific.hh"',
          { 'CPU_exec_context': 'O3DynInst' })
+CpuModel('InOrderCPU', 'inorder_cpu_exec.cc',
+         '#include "cpu/inorder/inorder_dyn_inst.hh"',
+         { 'CPU_exec_context': 'InOrderDynInst' })
diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py
new file mode 100644 (file)
index 0000000..a5e81a0
--- /dev/null
@@ -0,0 +1,80 @@
+# 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
+
+from m5.params import *
+from m5.proxy import *
+from m5 import build_env
+from BaseCPU import BaseCPU
+
+class InOrderCPU(BaseCPU):
+    type = 'InOrderCPU'
+    activity = Param.Unsigned(0, "Initial count")
+    numThreads = Param.Unsigned(1, "number of HW thread contexts")
+
+    cachePorts = Param.Unsigned("Cache Ports")
+    stageWidth = Param.Unsigned(1, "Stage width")
+
+    fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from")
+    dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from")
+    icache_port = Port("Instruction Port")
+    dcache_port = Port("Data Port")
+    _mem_ports = ['icache_port', 'dcache_port']
+
+    predType = Param.String("tournament", "Branch predictor type ('local', 'tournament')")
+    localPredictorSize = Param.Unsigned(2048, "Size of local predictor")
+    localCtrBits = Param.Unsigned(2, "Bits per counter")
+    localHistoryTableSize = Param.Unsigned(2048, "Size of local history table")
+    localHistoryBits = Param.Unsigned(11, "Bits for the local history")
+    globalPredictorSize = Param.Unsigned(8192, "Size of global predictor")
+    globalCtrBits = Param.Unsigned(2, "Bits per counter")
+    globalHistoryBits = Param.Unsigned(13, "Bits of history")
+    choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor")
+    choiceCtrBits = Param.Unsigned(2, "Bits of choice counters")
+
+    BTBEntries = Param.Unsigned(4096, "Number of BTB entries")
+    BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits")
+
+    RASSize = Param.Unsigned(16, "RAS size")
+
+    instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
+    functionTrace = Param.Bool(False, "Enable function trace")
+    functionTraceStart = Param.Tick(0, "Cycle to start function trace")
+    stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU")
+
+    memBlockSize = Param.Unsigned("Memory Block Size")
+
+    multLatency = Param.Unsigned(1, "Latency for Multiply Operations")
+    multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations")
+    div8Latency = Param.Unsigned(1, "Latency for 8-bit Divide Operations")
+    div8RepeatRate = Param.Unsigned(1, "Repeat Rate for 8-bit Divide Operations")
+    div16Latency = Param.Unsigned(1, "Latency for 16-bit Divide Operations")
+    div16RepeatRate = Param.Unsigned(1, "Repeat Rate for 16-bit Divide Operations")
+    div24Latency = Param.Unsigned(1, "Latency for 24-bit Divide Operations")
+    div24RepeatRate = Param.Unsigned(1, "Repeat Rate for 24-bit Divide Operations")
+    div32Latency = Param.Unsigned(1, "Latency for 32-bit Divide Operations")
+    div32RepeatRate = Param.Unsigned(1, "Repeat Rate for 32-bit Divide Operations")
diff --git a/src/cpu/inorder/InOrderTrace.py b/src/cpu/inorder/InOrderTrace.py
new file mode 100644 (file)
index 0000000..3453fa6
--- /dev/null
@@ -0,0 +1,35 @@
+# 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
+
+from m5.SimObject import SimObject
+from m5.params import *
+from InstTracer import InstTracer
+
+class InOrderTrace(InstTracer):
+    type = 'InOrderTrace'
+    cxx_class = 'Trace::InOrderTrace'
diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript
new file mode 100644 (file)
index 0000000..c7edd1d
--- /dev/null
@@ -0,0 +1,82 @@
+# -*- mode:python -*-
+
+# 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
+
+Import('*')
+
+if 'InOrderCPU' in env['CPU_MODELS']:
+       SimObject('InOrderCPU.py')
+       SimObject('InOrderTrace.py')
+
+       TraceFlag('ResReqCount')
+       TraceFlag('FreeList')
+       TraceFlag('InOrderCachePort')
+       TraceFlag('InOrderStage')
+       TraceFlag('InOrderStall')
+       TraceFlag('InOrderCPU')
+       TraceFlag('InOrderMDU')
+       TraceFlag('RegDepMap')
+       TraceFlag('Rename')
+       TraceFlag('InOrderDynInst')
+       TraceFlag('Resource')
+       TraceFlag('RefCount')
+
+       CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
+              'InOrderMDU', 'RegDepMap', 'Resource', 'Rename'])
+
+       Source('pipeline_traits.cc')        
+       Source('inorder_dyn_inst.cc')
+       Source('inorder_cpu_builder.cc')
+       Source('inorder_trace.cc')
+       Source('pipeline_stage.cc')
+       Source('first_stage.cc')
+       Source('resource.cc')
+       Source('resources/agen_unit.cc')
+       Source('resources/execution_unit.cc')
+       Source('resources/bpred_unit.cc')
+       Source('resources/branch_predictor.cc')
+       Source('resources/cache_unit.cc')
+       Source('resources/use_def.cc')
+       Source('resources/decode_unit.cc')
+       Source('resources/inst_buffer.cc')
+       Source('resources/graduation_unit.cc')
+       Source('resources/tlb_unit.cc')
+       Source('resources/fetch_seq_unit.cc')
+       Source('resources/mult_div_unit.cc')
+       Source('resource_pool.cc')
+       Source('reg_dep_map.cc')
+       Source('../o3/btb.cc')
+       Source('../o3/tournament_pred.cc')
+       Source('../o3/2bit_local_pred.cc')
+       Source('../o3/free_list.cc')
+       Source('../o3/rename_map.cc')
+       Source('../o3/ras.cc')
+       Source('thread_context.cc')
+       Source('cpu.cc')
+
diff --git a/src/cpu/inorder/SConsopts b/src/cpu/inorder/SConsopts
new file mode 100644 (file)
index 0000000..82ebd18
--- /dev/null
@@ -0,0 +1,33 @@
+# -*- mode:python -*-
+
+# 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
+
+Import('*')
+
+all_cpu_list.append('InOrderCPU')
diff --git a/src/cpu/inorder/comm.hh b/src/cpu/inorder/comm.hh
new file mode 100644 (file)
index 0000000..c687a9a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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_COMM_HH__
+#define __CPU_INORDER_COMM_HH__
+
+#include <vector>
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inst_seq.hh"
+#include "sim/host.hh"
+
+/** Struct that defines the information passed from in between stages */
+/** This information mainly goes forward through the pipeline. */
+struct InterStageStruct {
+    int size;
+    ThePipeline::DynInstPtr insts[ThePipeline::StageWidth];
+    bool squash;
+    bool branchMispredict;
+    bool branchTaken;
+    uint64_t mispredPC;
+    uint64_t nextPC;
+    InstSeqNum squashedSeqNum;
+    bool includeSquashInst;
+};
+
+/** Turn This into a Class */
+/** Struct that defines all backwards communication. */
+struct TimeStruct {
+    struct stageComm {
+        bool squash;
+        bool predIncorrect;
+        uint64_t branchAddr;
+
+        // @todo: Might want to package this kind of branch stuff into a single
+        // struct as it is used pretty frequently.
+        bool branchMispredict;
+        bool branchTaken;
+        uint64_t mispredPC;
+        uint64_t nextPC;
+
+        unsigned branchCount;
+
+        // Represents the instruction that has either been retired or
+        // squashed.  Similar to having a single bus that broadcasts the
+        // retired or squashed sequence number.
+        InstSeqNum doneSeqNum;
+        InstSeqNum bdelayDoneSeqNum;
+        bool squashDelaySlot;
+
+        //Just in case we want to do a commit/squash on a cycle
+        //(necessary for multiple ROBs?)
+        bool commitInsts;
+        InstSeqNum squashSeqNum;
+
+        // Communication specifically to the IQ to tell the IQ that it can
+        // schedule a non-speculative instruction.
+        InstSeqNum nonSpecSeqNum;
+
+        bool uncached;
+        ThePipeline::DynInstPtr uncachedLoad;
+
+        bool interruptPending;
+        bool clearInterrupt;
+    };
+
+    stageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads];
+
+    bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads];
+    bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads];
+};
+
+#endif //__CPU_INORDER_COMM_HH__
diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc
new file mode 100644 (file)
index 0000000..adbf645
--- /dev/null
@@ -0,0 +1,1322 @@
+/*
+ * 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 "arch/utility.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/activity.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/thread_context.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/cpu.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "mem/translating_port.hh"
+#include "sim/process.hh"
+//#include "sim/root.hh"
+#include "sim/stat_control.hh"
+#include <algorithm>
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InOrderCPU::TickEvent::TickEvent(InOrderCPU *c)
+  : Event(CPU_Tick_Pri), cpu(c)
+{ }
+
+
+void
+InOrderCPU::TickEvent::process()
+{
+    cpu->tick();
+}
+
+
+const char *
+InOrderCPU::TickEvent::description()
+{
+    return "InOrderCPU tick event";
+}
+
+InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type,
+                             Fault fault, unsigned _tid, unsigned _vpe)
+    : Event(CPU_Tick_Pri), cpu(_cpu)
+{
+    setEvent(e_type, fault, _tid, _vpe);
+}
+
+void
+InOrderCPU::CPUEvent::process()
+{
+    switch (cpuEventType)
+    {
+      case ActivateThread:
+        cpu->activateThread(tid);
+        break;
+
+      //@TODO: Consider Implementing "Suspend Thread" as Separate from Deallocate
+      case SuspendThread: // Suspend & Deallocate are same for now.
+        //cpu->suspendThread(tid);
+        //break;
+      case DeallocateThread:
+        cpu->deallocateThread(tid);
+        break;
+
+      case EnableVPEs:
+        cpu->enableVPEs(vpe);
+        break;
+
+      case DisableVPEs:
+        cpu->disableVPEs(tid, vpe);
+        break;
+
+      case EnableThreads:
+        cpu->enableThreads(vpe);
+        break;
+
+      case DisableThreads:
+        cpu->disableThreads(tid, vpe);
+        break;
+
+      case Trap:
+        cpu->trapCPU(fault, tid);
+        break;
+
+      default:
+        fatal("Unrecognized Event Type %d", cpuEventType);
+    }
+
+    cpu->cpuEventRemoveList.push(this);
+}
+
+const char *
+InOrderCPU::CPUEvent::description()
+{
+    return "InOrderCPU event";
+}
+
+void
+InOrderCPU::CPUEvent::scheduleEvent(int delay)
+{
+    if (squashed())
+      mainEventQueue.reschedule(this,curTick + cpu->ticks(delay));
+    else if (!scheduled())
+      mainEventQueue.schedule(this,curTick + cpu->ticks(delay));
+}
+
+void
+InOrderCPU::CPUEvent::unscheduleEvent()
+{
+    if (scheduled())
+        squash();
+}
+
+InOrderCPU::InOrderCPU(Params *params)
+    : BaseCPU(params),
+      cpu_id(params->cpu_id),
+      tickEvent(this),
+      miscRegFile(this),
+      timeBuffer(2 , 2),
+      removeInstsThisCycle(false),
+      activityRec(params->name, NumStages, 10, params->activity),
+      switchCount(0),
+      deferRegistration(false/*params->deferRegistration*/),
+      stageTracing(params->stageTracing),
+      numThreads(params->numThreads),
+      numVirtProcs(1)
+{
+    cpu_params = params;
+
+    resPool = new ResourcePool(this, params);
+//    resPool->init();
+
+    coreType = "default"; // eventually get this from params
+
+    _status = Idle;
+
+    // Resize for Multithreading CPUs
+    thread.resize(numThreads);
+
+    int active_threads = params->workload.size();
+
+    if (active_threads > MaxThreads) {
+        panic("Workload Size too large. Increase the 'MaxThreads'"
+              "in your InOrder implementation or "
+              "edit your workload size.");
+    }
+
+    // Bind the fetch & data ports from the resource pool.
+    fetchPortIdx = resPool->getPortIdx(params->fetchMemPort);
+    if (fetchPortIdx == 0) {
+        warn("Unable to find port to fetch instructions from.\n");
+    }
+
+    dataPortIdx = resPool->getPortIdx(params->dataMemPort);
+    if (dataPortIdx == 0) {
+        warn("Unable to find port for data.\n");
+    }
+
+
+    /* Use this port to for syscall emulation writes to memory. */
+    //Port *mem_port = NULL;
+    //TranslatingPort *trans_port = NULL;
+
+    for (int i = 0; i < numThreads; ++i) {
+        if (i < params->workload.size()) {
+            DPRINTF(InOrderCPU, "Workload[%i] process is %#x",
+                    i, this->thread[i]);
+            this->thread[i] = new Thread(this, i, params->workload[i],
+                                         i);
+
+            // Start thread's off in "Suspended" status
+            this->thread[i]->setStatus(ThreadContext::Suspended);
+
+        } else {
+            //Allocate Empty thread so M5 can use later
+            //when scheduling threads to CPU
+            Process* dummy_proc = params->workload[0]; //LiveProcess::createDummy();
+            this->thread[i] = new Thread(this, i, dummy_proc, i);
+
+            // Set Up Syscall Emulation Port
+            //this->thread[i]->setMemPort(trans_port);
+        }
+
+        // Setup the TC that will serve as the interface to the threads/CPU.
+        InOrderThreadContext *tc = new InOrderThreadContext;
+        tc->cpu = this;
+        tc->thread = this->thread[i];
+
+        // Give the thread the TC.
+        thread[i]->tc = tc;
+        thread[i]->setFuncExeInst(0);
+        globalSeqNum[i] = 1;
+
+        // Add the TC to the CPU's list of TC's.
+        this->threadContexts.push_back(tc);
+    }
+
+    // Initialize TimeBuffer Stage Queues
+    // For now just have these time buffers be pretty big.
+    // @note: This could be statically allocated but changes
+    // would have to be made to the standard time buffer class.
+    for (int stNum=0; stNum < NumStages - 1; stNum++) {
+        stageQueue[stNum] = new StageQueue(NumStages, NumStages);
+    }
+
+
+    // Set Up Pipeline Stages
+    for (int stNum=0; stNum < NumStages; stNum++) {
+        if (stNum == 0)
+            pipelineStage[stNum] = new FirstStage(params, stNum);
+        else
+            pipelineStage[stNum] = new PipelineStage(params, stNum);
+
+        pipelineStage[stNum]->setCPU(this);
+        pipelineStage[stNum]->setActiveThreads(&activeThreads);
+        pipelineStage[stNum]->setTimeBuffer(&timeBuffer);
+
+        // Take Care of 1st/Nth stages
+        if (stNum > 0)
+            pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]);
+        if (stNum < NumStages - 2)
+            pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum + 1]);
+    }
+
+    // Initialize thread specific variables
+    for (int tid=0; tid < numThreads; tid++) {
+        archRegDepMap[tid].setCPU(this);
+
+        nonSpecInstActive[tid] = false;
+        nonSpecSeqNum[tid] = 0;
+
+        squashSeqNum[tid] = MaxAddr;
+        lastSquashCycle[tid] = 0;
+
+        intRegFile[tid].clear();
+        floatRegFile[tid].clear();
+    }
+
+    // Update miscRegFile if necessary
+    if (numThreads > 1) {
+        miscRegFile.expandForMultithreading(numThreads, numVirtProcs);
+    }
+
+    miscRegFile.clear();
+
+    lastRunningCycle = curTick;
+    contextSwitch = false;
+
+    // Define dummy instructions and resource requests to be used.
+    DynInstPtr dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0);
+    dummyReq = new ResourceRequest(NULL, NULL, 0, 0, 0, 0);
+
+    // Reset CPU to reset state.
+#if FULL_SYSTEM
+    Fault resetFault = new ResetFault();
+    resetFault->invoke(tcBase());
+#else
+    reset();
+#endif
+
+    // Schedule First Tick Event, CPU will reschedule itself from here on out.
+    scheduleTickEvent(0);
+}
+
+
+void
+InOrderCPU::regStats()
+{
+    /* Register the Resource Pool's stats here.*/
+    resPool->regStats();
+
+    /* Register any of the InOrderCPU's stats here.*/
+    timesIdled
+        .name(name() + ".timesIdled")
+        .desc("Number of times that the entire CPU went into an idle state and"
+              " unscheduled itself")
+        .prereq(timesIdled);
+
+    idleCycles
+        .name(name() + ".idleCycles")
+        .desc("Total number of cycles that the CPU has spent unscheduled due "
+              "to idling")
+        .prereq(idleCycles);
+
+    threadCycles
+        .init(numThreads)
+        .name(name() + ".threadCycles")
+        .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)");
+
+    smtCycles
+        .name(name() + ".smtCycles")
+        .desc("Total number of cycles that the CPU was simultaneous multithreading.(SMT)");
+
+    committedInsts
+        .init(numThreads)
+        .name(name() + ".committedInsts")
+        .desc("Number of Instructions Simulated (Per-Thread)");
+
+    smtCommittedInsts
+        .init(numThreads)
+        .name(name() + ".smtCommittedInsts")
+        .desc("Number of SMT Instructions Simulated (Per-Thread)");
+
+    totalCommittedInsts
+        .name(name() + ".committedInsts_total")
+        .desc("Number of Instructions Simulated (Total)");
+
+    cpi
+        .name(name() + ".cpi")
+        .desc("CPI: Cycles Per Instruction (Per-Thread)")
+        .precision(6);
+    cpi = threadCycles / committedInsts;
+
+    smtCpi
+        .name(name() + ".smt_cpi")
+        .desc("CPI: Total SMT-CPI")
+        .precision(6);
+    smtCpi = smtCycles / smtCommittedInsts;
+
+    totalCpi
+        .name(name() + ".cpi_total")
+        .desc("CPI: Total CPI of All Threads")
+        .precision(6);
+    totalCpi = simTicks / totalCommittedInsts;
+
+    ipc
+        .name(name() + ".ipc")
+        .desc("IPC: Instructions Per Cycle (Per-Thread)")
+        .precision(6);
+    ipc =  committedInsts / threadCycles;
+
+    smtIpc
+        .name(name() + ".smt_ipc")
+        .desc("IPC: Total SMT-IPC")
+        .precision(6);
+    smtIpc = smtCommittedInsts / smtCycles;
+
+    totalIpc
+        .name(name() + ".ipc_total")
+        .desc("IPC: Total IPC of All Threads")
+        .precision(6);
+        totalIpc =  totalCommittedInsts / simTicks;
+
+    BaseCPU::regStats();
+}
+
+
+void
+InOrderCPU::tick()
+{
+    DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n");
+
+    ++numCycles;
+
+    //Tick each of the stages
+    for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
+        pipelineStage[stNum]->tick();
+    }
+
+    // Now advance the time buffers one tick
+    timeBuffer.advance();
+    for (int sqNum=0; sqNum < NumStages - 1; sqNum++) {
+        stageQueue[sqNum]->advance();
+    }
+    activityRec.advance();
+
+    // Any squashed requests, events, or insts then remove them now
+    cleanUpRemovedReqs();
+    cleanUpRemovedEvents();
+    cleanUpRemovedInsts();
+
+    // Re-schedule CPU for this cycle
+    if (!tickEvent.scheduled()) {
+        if (_status == SwitchedOut) {
+            // increment stat
+            lastRunningCycle = curTick;
+        } else if (!activityRec.active()) {
+            DPRINTF(InOrderCPU, "sleeping CPU.\n");
+            lastRunningCycle = curTick;
+            timesIdled++;
+        } else {
+            //Tick next_tick = curTick + cycles(1);
+            //tickEvent.schedule(next_tick);
+            mainEventQueue.schedule(&tickEvent, nextCycle(curTick + 1));
+            DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n", nextCycle() + curTick);
+        }
+    }
+
+    tickThreadStats();
+    updateThreadPriority();
+}
+
+
+void
+InOrderCPU::init()
+{
+    if (!deferRegistration) {
+        registerThreadContexts();
+    }
+
+    // Set inSyscall so that the CPU doesn't squash when initially
+    // setting up registers.
+    for (int i = 0; i < number_of_threads; ++i)
+        thread[i]->inSyscall = true;
+
+    for (int tid=0; tid < number_of_threads; tid++) {
+
+        ThreadContext *src_tc = thread[tid]->getTC();
+
+        // Threads start in the Suspended State
+        if (src_tc->status() != ThreadContext::Suspended) {
+            continue;
+        }
+
+    }
+
+    // Clear inSyscall.
+    for (int i = 0; i < number_of_threads; ++i)
+        thread[i]->inSyscall = false;
+
+    // Call Initializiation Routine for Resource Pool
+    resPool->init();
+}
+
+void
+InOrderCPU::readFunctional(Addr addr, uint32_t &buffer)
+{
+    tcBase()->getMemPort()->readBlob(addr, (uint8_t*)&buffer, sizeof(uint32_t));
+    buffer = gtoh(buffer);
+}
+
+void
+InOrderCPU::reset()
+{
+  miscRegFile.reset(coreType, numThreads, numVirtProcs, dynamic_cast<BaseCPU*>(this));
+}
+
+Port*
+InOrderCPU::getPort(const std::string &if_name, int idx)
+{
+    return resPool->getPort(if_name, idx);
+}
+
+void
+InOrderCPU::trap(Fault fault, unsigned tid, int delay)
+{
+    scheduleCpuEvent(Trap, fault, tid, 0/*vpe*/, delay);
+}
+
+void
+InOrderCPU::trapCPU(Fault fault, unsigned tid)
+{
+    fault->invoke(tcBase(tid));
+}
+
+void
+InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault,
+                           unsigned tid, unsigned vpe, unsigned delay)
+{
+    CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, vpe);
+
+    if (delay >= 0) {
+        DPRINTF(InOrderCPU, "Scheduling CPU Event Type #%i for cycle %i.\n",
+                c_event, curTick + delay);
+        mainEventQueue.schedule(cpu_event,curTick + delay);
+    } else {
+        cpu_event->process();
+        cpuEventRemoveList.push(cpu_event);
+    }
+
+    // Broadcast event to the Resource Pool
+    DynInstPtr dummy_inst = new InOrderDynInst(this, NULL, getNextEventNum(), tid);
+    resPool->scheduleEvent(c_event, dummy_inst, 0, 0, tid);
+}
+
+inline bool
+InOrderCPU::isThreadActive(unsigned tid)
+{
+  list<unsigned>::iterator isActive = std::find(
+        activeThreads.begin(), activeThreads.end(), tid);
+
+    return (isActive != activeThreads.end());
+}
+
+
+void
+InOrderCPU::activateThread(unsigned tid)
+{
+    if (!isThreadActive(tid)) {
+        DPRINTF(InOrderCPU, "Adding Thread %i to active threads list in CPU.\n",
+                tid);
+        activeThreads.push_back(tid);
+
+        wakeCPU();
+    }
+}
+
+void
+InOrderCPU::deactivateThread(unsigned tid)
+{
+    DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid);
+
+    if (isThreadActive(tid)) {
+        DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n",
+                tid);
+        list<unsigned>::iterator thread_it = std::find(activeThreads.begin(),
+                                                 activeThreads.end(), tid);
+
+        removePipelineStalls(*thread_it);
+
+        //@TODO: change stage status' to Idle?
+
+        activeThreads.erase(thread_it);
+    }
+}
+
+void
+InOrderCPU::removePipelineStalls(unsigned tid)
+{
+    DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n",
+            tid);
+
+    for (int stNum = 0; stNum < NumStages ; stNum++) {
+        pipelineStage[stNum]->removeStalls(tid);
+    }
+
+}
+bool
+InOrderCPU::isThreadInCPU(unsigned tid)
+{
+  list<unsigned>::iterator isCurrent = std::find(
+        currentThreads.begin(), currentThreads.end(), tid);
+
+    return (isCurrent != currentThreads.end());
+}
+
+void
+InOrderCPU::addToCurrentThreads(unsigned tid)
+{
+    if (!isThreadInCPU(tid)) {
+        DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n",
+                tid);
+        currentThreads.push_back(tid);
+    }
+}
+
+void
+InOrderCPU::removeFromCurrentThreads(unsigned tid)
+{
+    if (isThreadInCPU(tid)) {
+        DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n",
+                tid);
+        list<unsigned>::iterator isCurrent = std::find(
+            currentThreads.begin(), currentThreads.end(), tid);
+        currentThreads.erase(isCurrent);
+    }
+}
+
+bool
+InOrderCPU::isThreadSuspended(unsigned tid)
+{
+  list<unsigned>::iterator isSuspended = std::find(
+        suspendedThreads.begin(), suspendedThreads.end(), tid);
+
+    return (isSuspended!= suspendedThreads.end());
+}
+
+void
+InOrderCPU::enableVirtProcElement(unsigned vpe)
+{
+    DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling  "
+            "Enabling of concurrent virtual processor execution",
+            vpe);
+
+    scheduleCpuEvent(EnableVPEs, NoFault, 0/*tid*/, vpe);
+}
+
+void
+InOrderCPU::enableVPEs(unsigned vpe)
+{
+    DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Concurrent Execution "
+            "virtual processors %i", vpe);
+
+    list<unsigned>::iterator thread_it = currentThreads.begin();
+
+    while (thread_it != currentThreads.end()) {
+        if (!isThreadSuspended(*thread_it)) {
+            activateThread(*thread_it);
+        }
+        thread_it++;
+    }
+}
+
+void
+InOrderCPU::disableVirtProcElement(unsigned tid, unsigned vpe)
+{
+    DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling  "
+            "Disabling of concurrent virtual processor execution",
+            vpe);
+
+    scheduleCpuEvent(DisableVPEs, NoFault, 0/*tid*/, vpe);
+}
+
+void
+InOrderCPU::disableVPEs(unsigned tid, unsigned vpe)
+{
+    DPRINTF(InOrderCPU, "[vpe:%i]: Disabling Concurrent Execution of "
+            "virtual processors %i", vpe);
+
+    unsigned base_vpe = TheISA::getVirtProcNum(tcBase(tid));
+
+    list<unsigned>::iterator thread_it = activeThreads.begin();
+
+    std::vector<list<unsigned>::iterator> removeList;
+
+    while (thread_it != activeThreads.end()) {
+        if (base_vpe != vpe) {
+            removeList.push_back(thread_it);
+        }
+        thread_it++;
+    }
+
+    for (int i = 0; i < removeList.size(); i++) {
+        activeThreads.erase(removeList[i]);
+    }
+}
+
+void
+InOrderCPU::enableMultiThreading(unsigned vpe)
+{
+    // Schedule event to take place at end of cycle
+    DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling Enable Multithreading on "
+            "virtual processor %i", vpe);
+
+    scheduleCpuEvent(EnableThreads, NoFault, 0/*tid*/, vpe);
+}
+
+void
+InOrderCPU::enableThreads(unsigned vpe)
+{
+    DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Multithreading on "
+            "virtual processor %i", vpe);
+
+    list<unsigned>::iterator thread_it = currentThreads.begin();
+
+    while (thread_it != currentThreads.end()) {
+        if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) {
+            if (!isThreadSuspended(*thread_it)) {
+                activateThread(*thread_it);
+            }
+        }
+        thread_it++;
+    }
+}
+void
+InOrderCPU::disableMultiThreading(unsigned tid, unsigned vpe)
+{
+    // Schedule event to take place at end of cycle
+   DPRINTF(InOrderCPU, "[tid:%i]: Scheduling Disable Multithreading on "
+            "virtual processor %i", tid, vpe);
+
+    scheduleCpuEvent(DisableThreads, NoFault, tid, vpe);
+}
+
+void
+InOrderCPU::disableThreads(unsigned tid, unsigned vpe)
+{
+    DPRINTF(InOrderCPU, "[tid:%i]: Disabling Multithreading on "
+            "virtual processor %i", tid, vpe);
+
+    list<unsigned>::iterator thread_it = activeThreads.begin();
+
+    std::vector<list<unsigned>::iterator> removeList;
+
+    while (thread_it != activeThreads.end()) {
+        if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) {
+            removeList.push_back(thread_it);
+        }
+        thread_it++;
+    }
+
+    for (int i = 0; i < removeList.size(); i++) {
+        activeThreads.erase(removeList[i]);
+    }
+}
+
+void
+InOrderCPU::updateThreadPriority()
+{
+    if (activeThreads.size() > 1)
+    {
+        //DEFAULT TO ROUND ROBIN SCHEME
+        //e.g. Move highest priority to end of thread list
+        list<unsigned>::iterator list_begin = activeThreads.begin();
+        list<unsigned>::iterator list_end   = activeThreads.end();
+
+        unsigned high_thread = *list_begin;
+
+        activeThreads.erase(list_begin);
+
+        activeThreads.push_back(high_thread);
+    }
+}
+
+inline void
+InOrderCPU::tickThreadStats()
+{
+    /** Keep track of cycles that each thread is active */
+    list<unsigned>::iterator thread_it = activeThreads.begin();
+    while (thread_it != activeThreads.end()) {
+        threadCycles[*thread_it]++;
+        thread_it++;
+    }
+
+    // Keep track of cycles where SMT is active
+    if (activeThreads.size() > 1) {
+        smtCycles++;
+    }
+}
+
+void
+InOrderCPU::activateContext(unsigned tid, int delay)
+{
+    DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid);
+
+    scheduleCpuEvent(ActivateThread, NoFault, tid, 0/*vpe*/, delay);
+
+    // Be sure to signal that there's some activity so the CPU doesn't
+    // deschedule itself.
+    activityRec.activity();
+
+    _status = Running;
+}
+
+
+void
+InOrderCPU::suspendContext(unsigned tid, int delay)
+{
+    scheduleCpuEvent(SuspendThread, NoFault, tid, 0/*vpe*/, delay);
+    //_status = Idle;
+}
+
+void
+InOrderCPU::suspendThread(unsigned tid)
+{
+    DPRINTF(InOrderCPU,"[tid: %i]: Suspended ...\n", tid);
+    deactivateThread(tid);
+}
+
+void
+InOrderCPU::deallocateContext(unsigned tid, int delay)
+{
+    scheduleCpuEvent(DeallocateThread, NoFault, tid, 0/*vpe*/, delay);
+}
+
+void
+InOrderCPU::deallocateThread(unsigned tid)
+{
+    DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid);
+
+    //removeThread(tid);
+
+    removeFromCurrentThreads(tid);
+
+    deactivateThread(tid);
+
+    squashThreadInPipeline(tid);
+}
+
+void
+InOrderCPU::squashThreadInPipeline(unsigned tid)
+{
+    //Squash all instructions in each stage
+    for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
+        pipelineStage[stNum]->squash(0 /*seq_num*/, tid);
+    }
+}
+
+void
+InOrderCPU::haltContext(unsigned tid, int delay)
+{
+    DPRINTF(InOrderCPU, "[tid:%i]: Halt context called.\n", tid);
+
+    // Halt is same thing as deallocate for now
+    // @TODO: Differentiate between halt & deallocate in the CPU
+    // model
+    deallocateContext(tid, delay);
+}
+
+void
+InOrderCPU::insertThread(unsigned tid)
+{
+    panic("Unimplemented Function\n.");
+}
+
+void
+InOrderCPU::removeThread(unsigned tid)
+{
+    DPRINTF(InOrderCPU, "Removing Thread %i from CPU.\n", tid);
+
+    /** Broadcast to CPU resources*/
+}
+
+void
+InOrderCPU::activateWhenReady(int tid)
+{
+    panic("Unimplemented Function\n.");
+}
+
+
+void
+InOrderCPU::signalSwitched()
+{
+    panic("Unimplemented Function\n.");
+}
+
+
+void
+InOrderCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+    panic("Take Over From Another CPU\n.");
+}
+
+uint64_t
+InOrderCPU::readPC(unsigned tid)
+{
+    return PC[tid];
+}
+
+
+void
+InOrderCPU::setPC(Addr new_PC, unsigned tid)
+{
+    PC[tid] = new_PC;
+}
+
+
+uint64_t
+InOrderCPU::readNextPC(unsigned tid)
+{
+    return nextPC[tid];
+}
+
+
+void
+InOrderCPU::setNextPC(uint64_t new_NPC, unsigned tid)
+{
+    nextPC[tid] = new_NPC;
+}
+
+
+uint64_t
+InOrderCPU::readNextNPC(unsigned tid)
+{
+    return nextNPC[tid];
+}
+
+
+void
+InOrderCPU::setNextNPC(uint64_t new_NNPC, unsigned tid)
+{
+    nextNPC[tid] = new_NNPC;
+}
+
+uint64_t
+InOrderCPU::readIntReg(int reg_idx, unsigned tid)
+{
+    return intRegFile[tid].readReg(reg_idx);
+}
+
+FloatReg
+InOrderCPU::readFloatReg(int reg_idx, unsigned tid, int width)
+{
+
+    return floatRegFile[tid].readReg(reg_idx, width);
+}
+
+FloatRegBits
+InOrderCPU::readFloatRegBits(int reg_idx, unsigned tid, int width)
+{;
+    return floatRegFile[tid].readRegBits(reg_idx, width);
+}
+
+void
+InOrderCPU::setIntReg(int reg_idx, uint64_t val, unsigned tid)
+{
+    intRegFile[tid].setReg(reg_idx, val);
+}
+
+
+void
+InOrderCPU::setFloatReg(int reg_idx, FloatReg val, unsigned tid, int width)
+{
+    floatRegFile[tid].setReg(reg_idx, val, width);
+}
+
+
+void
+InOrderCPU::setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, int width)
+{
+    floatRegFile[tid].setRegBits(reg_idx, val, width);
+}
+
+uint64_t
+InOrderCPU::readRegOtherThread(unsigned reg_idx, unsigned tid)
+{
+    // If Default value is set, then retrieve target thread
+    if (tid == -1) {
+        tid = TheISA::getTargetThread(tcBase(tid));
+    }
+
+    if (reg_idx < FP_Base_DepTag) {                   // Integer Register File
+        return readIntReg(reg_idx, tid);
+    } else if (reg_idx < Ctrl_Base_DepTag) {          // Float Register File
+        reg_idx -= FP_Base_DepTag;
+        return readFloatRegBits(reg_idx, tid);
+    } else {
+        reg_idx -= Ctrl_Base_DepTag;
+        return readMiscReg(reg_idx, tid);  // Misc. Register File
+    }
+}
+void
+InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val, unsigned tid)
+{
+    // If Default value is set, then retrieve target thread
+    if (tid == -1) {
+        tid = TheISA::getTargetThread(tcBase(tid));
+    }
+
+    if (reg_idx < FP_Base_DepTag) {            // Integer Register File
+        setIntReg(reg_idx, val, tid);
+    } else if (reg_idx < Ctrl_Base_DepTag) {   // Float Register File
+        reg_idx -= FP_Base_DepTag;
+        setFloatRegBits(reg_idx, val, tid);
+    } else {
+        reg_idx -= Ctrl_Base_DepTag;
+        setMiscReg(reg_idx, val, tid); // Misc. Register File
+    }
+}
+
+MiscReg
+InOrderCPU::readMiscRegNoEffect(int misc_reg, unsigned tid)
+{
+    return miscRegFile.readRegNoEffect(misc_reg, tid);
+}
+
+MiscReg
+InOrderCPU::readMiscReg(int misc_reg, unsigned tid)
+{
+    return miscRegFile.readReg(misc_reg, tcBase(tid), tid);
+}
+
+void
+InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid)
+{
+    miscRegFile.setRegNoEffect(misc_reg, val, tid);
+}
+
+void
+InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
+{
+    miscRegFile.setReg(misc_reg, val, tcBase(tid), tid);
+}
+
+
+InOrderCPU::ListIt
+InOrderCPU::addInst(DynInstPtr &inst)
+{
+    int tid = inst->readTid();
+
+    instList[tid].push_back(inst);
+
+    return --(instList[tid].end());
+}
+
+void
+InOrderCPU::instDone(DynInstPtr inst, unsigned tid)
+{
+    // Set the CPU's PCs - This contributes to the precise state of the CPU which can be used
+    // when restoring a thread to the CPU after a fork or after an exception
+    // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if it's a branch or not
+    setPC(inst->readPC(), tid);
+    setNextPC(inst->readNextPC(), tid);
+    setNextNPC(inst->readNextNPC(), tid);
+
+    // Finalize Trace Data For Instruction
+    if (inst->traceData) {
+        //inst->traceData->setCycle(curTick);
+        inst->traceData->setFetchSeq(inst->seqNum);
+        //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst);
+        inst->traceData->dump();
+        delete inst->traceData;
+        inst->traceData = NULL;
+    }
+
+    // Set Last Graduated Instruction In Thread State
+    //thread[tid]->lastGradInst = inst;
+
+    // Increment thread-state's instruction count
+    thread[tid]->numInst++;
+
+    // Increment thread-state's instruction stats
+    thread[tid]->numInsts++;
+
+    // Count committed insts per thread stats
+    committedInsts[tid]++;
+
+    // Count total insts committed stat
+    totalCommittedInsts++;
+
+    // Count SMT-committed insts per thread stat
+    if (numActiveThreads() > 1) {
+        smtCommittedInsts[tid]++;
+    }
+
+    // Check for instruction-count-based events.
+    comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
+
+    // Broadcast to other resources an instruction
+    // has been completed
+    resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, tid);
+
+    // Finally, remove instruction from CPU
+    removeInst(inst);
+}
+
+void
+InOrderCPU::addToRemoveList(DynInstPtr &inst)
+{
+    removeInstsThisCycle = true;
+
+    removeList.push(inst->getInstListIt());
+}
+
+void
+InOrderCPU::removeInst(DynInstPtr &inst)
+{
+    DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x "
+            "[sn:%lli]\n",
+            inst->threadNumber, inst->readPC(), inst->seqNum);
+
+    removeInstsThisCycle = true;
+
+    // Remove the instruction.
+    removeList.push(inst->getInstListIt());
+}
+
+void
+InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num,
+                                  unsigned tid)
+{
+    //assert(!instList[tid].empty());
+
+    removeInstsThisCycle = true;
+
+    ListIt inst_iter = instList[tid].end();
+
+    inst_iter--;
+
+    DPRINTF(InOrderCPU, "Deleting instructions from CPU instruction "
+            "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
+            tid, seq_num, (*inst_iter)->seqNum);
+
+    while ((*inst_iter)->seqNum > seq_num) {
+
+        bool break_loop = (inst_iter == instList[tid].begin());
+
+        squashInstIt(inst_iter, tid);
+
+        inst_iter--;
+
+        if (break_loop)
+            break;
+    }
+}
+
+
+inline void
+InOrderCPU::squashInstIt(const ListIt &instIt, const unsigned &tid)
+{
+    if ((*instIt)->threadNumber == tid) {
+        DPRINTF(InOrderCPU, "Squashing instruction, "
+                "[tid:%i] [sn:%lli] PC %#x\n",
+                (*instIt)->threadNumber,
+                (*instIt)->seqNum,
+                (*instIt)->readPC());
+
+        (*instIt)->setSquashed();
+
+        removeList.push(instIt);
+    }
+}
+
+
+void
+InOrderCPU::cleanUpRemovedInsts()
+{
+    while (!removeList.empty()) {
+        DPRINTF(InOrderCPU, "Removing instruction, "
+                "[tid:%i] [sn:%lli] PC %#x\n",
+                (*removeList.front())->threadNumber,
+                (*removeList.front())->seqNum,
+                (*removeList.front())->readPC());
+
+        DynInstPtr inst = *removeList.front();
+        int tid = inst->threadNumber;
+
+        // Make Sure Resource Schedule Is Emptied Out
+        ThePipeline::ResSchedule *inst_sched = &inst->resSched;
+        while (!inst_sched->empty()) {
+            ThePipeline::ScheduleEntry* sch_entry = inst_sched->top();
+            inst_sched->pop();
+            delete sch_entry;
+        }
+
+        // Remove From Register Dependency Map, If Necessary
+        archRegDepMap[(*removeList.front())->threadNumber].
+            remove((*removeList.front()));
+
+
+        // Clear if Non-Speculative
+        if (inst->staticInst &&
+              inst->seqNum == nonSpecSeqNum[tid] &&
+                nonSpecInstActive[tid] == true) {
+            nonSpecInstActive[tid] = false;
+        }
+
+        instList[tid].erase(removeList.front());
+
+        removeList.pop();
+
+        DPRINTF(RefCount, "pop from remove list: [sn:%i]: Refcount = %i.\n",
+                inst->seqNum,
+                0/*inst->curCount()*/);
+
+    }
+
+    removeInstsThisCycle = false;
+}
+
+void
+InOrderCPU::cleanUpRemovedReqs()
+{
+    while (!reqRemoveList.empty()) {
+        ResourceRequest *res_req = reqRemoveList.front();
+
+        DPRINTF(RefCount, "[tid:%i]: Removing Request, "
+                "[sn:%lli] [slot:%i] [stage_num:%i] [res:%s] [refcount:%i].\n",
+                res_req->inst->threadNumber,
+                res_req->inst->seqNum,
+                res_req->getSlot(),
+                res_req->getStageNum(),
+                res_req->res->name(),
+                0/*res_req->inst->curCount()*/);
+
+        reqRemoveList.pop();
+
+        delete res_req;
+
+        DPRINTF(RefCount, "after remove request: [sn:%i]: Refcount = %i.\n",
+                res_req->inst->seqNum,
+                0/*res_req->inst->curCount()*/);
+    }
+}
+
+void
+InOrderCPU::cleanUpRemovedEvents()
+{
+    while (!cpuEventRemoveList.empty()) {
+        Event *cpu_event = cpuEventRemoveList.front();
+        cpuEventRemoveList.pop();
+        delete cpu_event;
+    }
+}
+
+/*
+
+void
+InOrderCPU::removeAllInsts()
+{
+    instList.clear();
+}
+*/
+
+void
+InOrderCPU::dumpInsts()
+{
+    int num = 0;
+
+    ListIt inst_list_it = instList[0].begin();
+
+    cprintf("Dumping Instruction List\n");
+
+    while (inst_list_it != instList[0].end()) {
+        cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
+                "Squashed:%i\n\n",
+                num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
+                (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
+                (*inst_list_it)->isSquashed());
+        inst_list_it++;
+        ++num;
+    }
+}
+/*
+
+void
+InOrderCPU::wakeDependents(DynInstPtr &inst)
+{
+    iew.wakeDependents(inst);
+}
+*/
+
+void
+InOrderCPU::wakeCPU()
+{
+    if (/*activityRec.active() || */tickEvent.scheduled()) {
+        DPRINTF(Activity, "CPU already running.\n");
+        return;
+    }
+
+    DPRINTF(Activity, "Waking up CPU\n");
+
+    //idleCycles += (curTick - 1) - lastRunningCycle;
+
+    mainEventQueue.schedule(&tickEvent, curTick);
+}
+
+void
+InOrderCPU::syscall(int64_t callnum, int tid)
+{
+    DPRINTF(InOrderCPU, "[tid:%i] Executing syscall().\n\n", tid);
+
+    DPRINTF(Activity,"Activity: syscall() called.\n");
+
+    // Temporarily increase this by one to account for the syscall
+    // instruction.
+    ++(this->thread[tid]->funcExeInst);
+
+    // Execute the actual syscall.
+    this->thread[tid]->syscall(callnum);
+
+    // Decrease funcExeInst by one as the normal commit will handle
+    // incrementing it.
+    --(this->thread[tid]->funcExeInst);
+
+    // Clear Non-Speculative Block Variable
+    nonSpecInstActive[tid] = false;
+}
+
+IntReg
+InOrderCPU::getSyscallArg(int idx, int tid)
+{
+    return readIntReg(ArgumentReg0 + idx, tid);
+}
+
+void
+InOrderCPU::setSyscallArg(int idx, IntReg val, int tid)
+{
+    setIntReg(ArgumentReg0 + idx, val, tid);
+}
+
+void
+InOrderCPU::setSyscallReturn(SyscallReturn return_value, int tid)
+{
+    if (return_value.successful()) {
+        // no error
+        setIntReg(SyscallSuccessReg, 0, tid);
+        setIntReg(ReturnValueReg, return_value.value(), tid);
+    } else {
+        // got an error, return details
+        setIntReg(SyscallSuccessReg, (IntReg) -1, tid);
+        setIntReg(ReturnValueReg, -return_value.value(), tid);
+    }
+}
+
+Fault
+InOrderCPU::read(DynInstPtr inst)
+{
+    Resource *mem_res = resPool->getResource(dataPortIdx);
+    return mem_res->doDataAccess(inst);
+}
+
+Fault
+InOrderCPU::write(DynInstPtr inst)
+{
+    Resource *mem_res = resPool->getResource(dataPortIdx);
+    return mem_res->doDataAccess(inst);
+}
diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh
new file mode 100644 (file)
index 0000000..cd1eb6f
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * 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_CPU_HH__
+#define __CPU_INORDER_CPU_HH__
+
+#include <iostream>
+#include <list>
+#include <queue>
+#include <set>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "config/full_system.hh"
+#include "cpu/activity.hh"
+#include "cpu/base.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/pipeline_stage.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+#include "cpu/o3/dep_graph.hh"
+#include "cpu/o3/rename_map.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+#include "sim/process.hh"
+
+class ThreadContext;
+class MemInterface;
+class MemObject;
+class Process;
+class ResourcePool;
+
+class InOrderCPU : public BaseCPU
+{
+
+  protected:
+    typedef ThePipeline::Params Params;
+    typedef InOrderThreadState Thread;
+
+   //ISA TypeDefs
+    typedef TheISA::IntReg IntReg;
+    typedef TheISA::FloatReg FloatReg;
+    typedef TheISA::FloatRegBits FloatRegBits;
+    typedef TheISA::MiscReg MiscReg;
+    typedef TheISA::RegFile RegFile;
+    typedef SimpleRenameMap RenameMap;
+
+    //DynInstPtr TypeDefs
+    typedef ThePipeline::DynInstPtr DynInstPtr;
+    typedef std::list<DynInstPtr>::iterator ListIt;
+
+    //TimeBuffer TypeDefs
+    typedef TimeBuffer<InterStageStruct> StageQueue;
+
+    friend class Resource;
+
+  public:
+    /** Constructs a CPU with the given parameters. */
+    InOrderCPU(Params *params);
+
+    /** CPU ID */
+    int cpu_id;
+
+    /** Type of core that this is */
+    std::string coreType;
+
+    int readCpuId() { return cpu_id; }
+
+    void setCpuId(int val) { cpu_id = val; }
+
+    Params *cpu_params;
+
+    TheISA::ITB * itb;
+    TheISA::DTB * dtb;
+
+  public:
+    enum Status {
+        Running,
+        Idle,
+        Halted,
+        Blocked,
+        SwitchedOut
+    };
+
+    /** Overall CPU status. */
+    Status _status;
+
+  private:
+    /** Define TickEvent for the CPU */
+    class TickEvent : public Event
+    {
+      private:
+        /** Pointer to the CPU. */
+        InOrderCPU *cpu;
+
+      public:
+        /** Constructs a tick event. */
+        TickEvent(InOrderCPU *c);
+
+        /** Processes a tick event, calling tick() on the CPU. */
+        void process();
+
+        /** Returns the description of the tick event. */
+        const char *description();
+    };
+
+    /** The tick event used for scheduling CPU ticks. */
+    TickEvent tickEvent;
+
+    /** Schedule tick event, regardless of its current state. */
+    void scheduleTickEvent(int delay)
+    {
+        if (tickEvent.squashed())
+          mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay)));
+        else if (!tickEvent.scheduled())
+          mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay)));
+    }
+
+    /** Unschedule tick event, regardless of its current state. */
+    void unscheduleTickEvent()
+    {
+        if (tickEvent.scheduled())
+            tickEvent.squash();
+    }
+
+  public:
+    // List of Events That can be scheduled from
+    // within the CPU.
+    // NOTE(1): The Resource Pool also uses this event list
+    // to schedule events broadcast to all resources interfaces
+    // NOTE(2): CPU Events usually need to schedule a corresponding resource
+    // pool event.
+    enum CPUEventType {
+        ActivateThread,
+        DeallocateThread,
+        SuspendThread,
+        DisableThreads,
+        EnableThreads,
+        DisableVPEs,
+        EnableVPEs,
+        Trap,
+        InstGraduated,
+        SquashAll,
+        UpdatePCs,
+        NumCPUEvents
+    };
+
+    /** Define CPU Event */
+    class CPUEvent : public Event
+    {
+      protected:
+        InOrderCPU *cpu;
+
+      public:
+        CPUEventType cpuEventType;
+        unsigned tid;
+        unsigned vpe;
+        Fault fault;
+
+      public:
+        /** Constructs a CPU event. */
+        CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault,
+                 unsigned _tid, unsigned _vpe);
+
+        /** Set Type of Event To Be Scheduled */
+        void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe)
+        {
+            fault = _fault;
+            cpuEventType = e_type;
+            tid = _tid;
+            vpe = _vpe;
+        }
+
+        /** Processes a resource event. */
+        virtual void process();
+
+        /** Returns the description of the resource event. */
+        const char *description();
+
+        /** Schedule Event */
+        void scheduleEvent(int delay);
+
+        /** Unschedule This Event */
+        void unscheduleEvent();
+    };
+
+    /** Schedule a CPU Event */
+    void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid,
+                          unsigned vpe, unsigned delay = 0);
+
+  public:
+    /** Interface between the CPU and CPU resources. */
+    ResourcePool *resPool;
+
+    /** Instruction used to signify that there is no *real* instruction in buffer slot */
+    DynInstPtr dummyBufferInst;
+
+    /** Used by resources to signify a denied access to a resource. */
+    ResourceRequest *dummyReq;
+
+    /** Identifies the resource id that identifies a fetch
+     * access unit.
+     */
+    unsigned fetchPortIdx;
+
+    /** Identifies the resource id that identifies a data
+     * access unit.
+     */
+    unsigned dataPortIdx;
+
+    /** The Pipeline Stages for the CPU */
+    PipelineStage *pipelineStage[ThePipeline::NumStages];
+
+    TheISA::IntReg PC[ThePipeline::MaxThreads];
+    TheISA::IntReg nextPC[ThePipeline::MaxThreads];
+    TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
+
+    /** The Register File for the CPU */
+    /** @TODO: This regFile wont be a sufficient solution for out-of-order, add register
+     *  files as a resource in order to handle ths problem
+     */
+    TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];;
+    TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];;
+    TheISA::MiscRegFile miscRegFile;
+
+    /** Dependency Tracker for Integer & Floating Point Regs */
+    RegDepMap archRegDepMap[ThePipeline::MaxThreads];
+
+    /** Global communication structure */
+    TimeBuffer<TimeStruct> timeBuffer;
+
+    /** Communication structure that sits in between pipeline stages */
+    StageQueue *stageQueue[ThePipeline::NumStages-1];
+
+  public:
+
+    /** Registers statistics. */
+    void regStats();
+
+    /** Ticks CPU, calling tick() on each stage, and checking the overall
+     *  activity to see if the CPU should deschedule itself.
+     */
+    void tick();
+
+    /** Initialize the CPU */
+    void init();
+
+    /** Reset State in the CPU */
+    void reset();
+
+    /** Get a Memory Port */
+    Port* getPort(const std::string &if_name, int idx = 0);
+
+    /** trap() - sets up a trap event on the cpuTraps to handle given fault.
+     *  trapCPU() - Traps to handle given fault
+     */
+    void trap(Fault fault, unsigned tid, int delay = 0);
+    void trapCPU(Fault fault, unsigned tid);
+
+    /** Setup CPU to insert a thread's context */
+    void insertThread(unsigned tid);
+
+    /** Remove all of a thread's context from CPU */
+    void removeThread(unsigned tid);
+
+    /** Add Thread to Active Threads List. */
+    void activateContext(unsigned tid, int delay = 0);
+    void activateThread(unsigned tid);
+
+    /** Remove Thread from Active Threads List */
+    void suspendContext(unsigned tid, int delay = 0);
+    void suspendThread(unsigned tid);
+
+    /** Remove Thread from Active Threads List &&
+     *  Remove Thread Context from CPU.
+     */
+    void deallocateContext(unsigned tid, int delay = 0);
+    void deallocateThread(unsigned tid);
+    void deactivateThread(unsigned tid);
+
+    /** Remove Thread from Active Threads List &&
+     *  Remove Thread Context from CPU.
+     */
+    void haltContext(unsigned tid, int delay = 0);
+
+    void removePipelineStalls(unsigned tid);
+
+    void squashThreadInPipeline(unsigned tid);
+
+    /// Notify the CPU to enable a virtual processor element.
+    virtual void enableVirtProcElement(unsigned vpe);
+    void enableVPEs(unsigned vpe);
+
+    /// Notify the CPU to disable a virtual processor element.
+    virtual void disableVirtProcElement(unsigned tid, unsigned vpe);
+    void disableVPEs(unsigned tid, unsigned vpe);
+
+    /// Notify the CPU that multithreading is enabled.
+    virtual void enableMultiThreading(unsigned vpe);
+    void enableThreads(unsigned vpe);
+
+    /// Notify the CPU that multithreading is disabled.
+    virtual void disableMultiThreading(unsigned tid, unsigned vpe);
+    void disableThreads(unsigned tid, unsigned vpe);
+
+    // Sets a thread-rescheduling condition.
+    void setThreadRescheduleCondition(uint32_t tid)
+    {
+      //@TODO: IMPLEMENT ME
+    }
+
+    /** Activate a Thread When CPU Resources are Available. */
+    void activateWhenReady(int tid);
+
+    /** Add or Remove a Thread Context in the CPU. */
+    void doContextSwitch();
+
+    /** Update The Order In Which We Process Threads. */
+    void updateThreadPriority();
+
+    /** Switches a Pipeline Stage to Active. (Unused currently) */
+    void switchToActive(int stage_idx)
+    { /*pipelineStage[stage_idx]->switchToActive();*/ }
+
+    /** Switches out this CPU. (Unused currently) */
+    //void switchOut(Sampler *sampler);
+
+    /** Signals to this CPU that a stage has completed switching out. (Unused currently)*/
+    void signalSwitched();
+
+    /** Takes over from another CPU. (Unused currently)*/
+    void takeOverFrom(BaseCPU *oldCPU);
+
+    /** Get the current instruction sequence number, and increment it. */
+    InstSeqNum getAndIncrementInstSeq(unsigned tid)
+    { return globalSeqNum[tid]++; }
+
+    /** Get the current instruction sequence number, and increment it. */
+    InstSeqNum nextInstSeqNum(unsigned tid)
+    { return globalSeqNum[tid]; }
+
+    /** Increment Instruction Sequence Number */
+    void incrInstSeqNum(unsigned tid)
+    { globalSeqNum[tid]++; }
+
+    /** Set Instruction Sequence Number */
+    void setInstSeqNum(unsigned tid, InstSeqNum seq_num)
+    {
+        globalSeqNum[tid] = seq_num;
+    }
+
+    InstSeqNum getNextEventNum()
+    {
+        return cpuEventNum++;
+    }
+
+    /** Get instruction asid. */
+    int getInstAsid(unsigned tid)
+    { return thread[tid]->getInstAsid(); }
+
+    /** Get data asid. */
+    int getDataAsid(unsigned tid)
+    { return thread[tid]->getDataAsid(); }
+
+    /** Register file accessors  */
+    uint64_t readIntReg(int reg_idx, unsigned tid);
+
+    FloatReg readFloatReg(int reg_idx, unsigned tid,
+                          int width = TheISA::SingleWidth);
+
+    FloatRegBits readFloatRegBits(int reg_idx, unsigned tid,
+                                  int width = TheISA::SingleWidth);
+
+    void setIntReg(int reg_idx, uint64_t val, unsigned tid);
+
+    void setFloatReg(int reg_idx, FloatReg val,  unsigned tid,
+                     int width = TheISA::SingleWidth);
+
+    void setFloatRegBits(int reg_idx, FloatRegBits val,  unsigned tid,
+                         int width = TheISA::SingleWidth);
+
+    /** Reads a miscellaneous register. */
+    MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
+
+    /** Reads a misc. register, including any side effects the read
+     * might have as defined by the architecture.
+     */
+    MiscReg readMiscReg(int misc_reg, unsigned tid);
+
+    /** Sets a miscellaneous register. */
+    void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid);
+
+    /** Sets a misc. register, including any side effects the write
+     * might have as defined by the architecture.
+     */
+    void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid);
+
+    /** Reads a int/fp/misc reg. from another thread depending on ISA-defined
+     *  target thread
+     */
+    uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1);
+
+    /** Sets a int/fp/misc reg. from another thread depending on an ISA-defined
+     * target thread
+     */
+    void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid);
+
+    /** Reads the commit PC of a specific thread. */
+    uint64_t readPC(unsigned tid);
+
+    /** Sets the commit PC of a specific thread. */
+    void setPC(Addr new_PC, unsigned tid);
+
+    /** Reads the next PC of a specific thread. */
+    uint64_t readNextPC(unsigned tid);
+
+    /** Sets the next PC of a specific thread. */
+    void setNextPC(uint64_t val, unsigned tid);
+
+    /** Reads the next NPC of a specific thread. */
+    uint64_t readNextNPC(unsigned tid);
+
+    /** Sets the next NPC of a specific thread. */
+    void setNextNPC(uint64_t val, unsigned tid);
+
+    /** Add Destination Register To Dependency Maps */
+    //void addToRegDepMap(DynInstPtr &inst);
+
+    /** Function to add instruction onto the head of the list of the
+     *  instructions.  Used when new instructions are fetched.
+     */
+    ListIt addInst(DynInstPtr &inst);
+
+    /** Function to tell the CPU that an instruction has completed. */
+    void instDone(DynInstPtr inst, unsigned tid);
+
+    /** Add Instructions to the CPU Remove List*/
+    void addToRemoveList(DynInstPtr &inst);
+
+    /** Remove an instruction from CPU */
+    void removeInst(DynInstPtr &inst);
+
+    /** Remove all instructions younger than the given sequence number. */
+    void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid);
+
+    /** Removes the instruction pointed to by the iterator. */
+    inline void squashInstIt(const ListIt &instIt, const unsigned &tid);
+
+    /** Cleans up all instructions on the instruction remove list. */
+    void cleanUpRemovedInsts();
+
+    /** Cleans up all instructions on the request remove list. */
+    void cleanUpRemovedReqs();
+
+    /** Cleans up all instructions on the CPU event remove list. */
+    void cleanUpRemovedEvents();
+
+    /** Debug function to print all instructions on the list. */
+    void dumpInsts();
+
+    /** Translates instruction requestion in syscall emulation mode. */
+    Fault translateInstReq(RequestPtr &req, Thread *thread)
+    {
+        return thread->getProcessPtr()->pTable->translate(req);
+    }
+
+    /** Translates data read request in syscall emulation mode. */
+    Fault translateDataReadReq(RequestPtr &req, Thread *thread)
+    {
+        return thread->getProcessPtr()->pTable->translate(req);
+    }
+
+    /** Translates data write request in syscall emulation mode. */
+    Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
+    {
+        return thread->getProcessPtr()->pTable->translate(req);
+    }
+
+    /** Forwards an instruction read to the appropriate data
+     *  resource (indexes into Resource Pool thru "dataPortIdx")
+     */
+    Fault read(DynInstPtr inst);
+
+    /** Forwards an instruction write. to the appropriate data
+     *  resource (indexes into Resource Pool thru "dataPortIdx")
+     */
+    Fault write(DynInstPtr inst);
+
+    /** Executes a syscall.*/
+    void syscall(int64_t callnum, int tid);
+
+    /** Gets a syscall argument. */
+    IntReg getSyscallArg(int i, int tid);
+
+    /** Used to shift args for indirect syscall. */
+    void setSyscallArg(int i, IntReg val, int tid);
+
+    /** Sets the return value of a syscall. */
+    void setSyscallReturn(SyscallReturn return_value, int tid);
+
+  public:
+    /** Per-Thread List of all the instructions in flight. */
+    std::list<DynInstPtr> instList[ThePipeline::MaxThreads];
+
+    /** List of all the instructions that will be removed at the end of this
+     *  cycle.
+     */
+    std::queue<ListIt> removeList;
+
+    /** List of all the resource requests that will be removed at the end of this
+     *  cycle.
+     */
+    std::queue<ResourceRequest*> reqRemoveList;
+
+    /** List of all the cpu event requests that will be removed at the end of
+     *  the current cycle.
+     */
+    std::queue<Event*> cpuEventRemoveList;
+
+#ifdef DEBUG
+    /** Debug structure to keep track of the sequence numbers still in
+     * flight.
+     */
+    std::set<InstSeqNum> snList;
+#endif
+
+    /** Records if instructions need to be removed this cycle due to
+     *  being retired or squashed.
+     */
+    bool removeInstsThisCycle;
+
+    /** True if there is non-speculative Inst Active In Pipeline. Lets any
+     * execution unit know, NOT to execute while the instruction is active.
+     */
+    bool nonSpecInstActive[ThePipeline::MaxThreads];
+
+    /** Instruction Seq. Num of current non-speculative instruction. */
+    InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads];
+
+    /** Instruction Seq. Num of last instruction squashed in pipeline */
+    InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
+
+    /** Last Cycle that the CPU squashed instruction end. */
+    Tick lastSquashCycle[ThePipeline::MaxThreads];
+
+    std::list<unsigned> fetchPriorityList;
+
+     /** Rename Map for architectural-to-physical register mappings.
+      *  In a In-order processor, the mapping is fixed
+      *  (e.g. Thread 1: 0-31, Thread 1: 32-63, etc.)
+      *  In a Out-of-Order processor, this is used to maintain
+      *  sequential consistency (?right word here?).
+      */
+     RenameMap renameMap[ThePipeline::MaxThreads];
+
+  protected:
+    /** Active Threads List */
+    std::list<unsigned> activeThreads;
+
+    /** Current Threads List */
+    std::list<unsigned> currentThreads;
+
+    /** Suspended Threads List */
+    std::list<unsigned> suspendedThreads;
+
+    /** Thread Status Functions (Unused Currently) */
+    bool isThreadInCPU(unsigned tid);
+    bool isThreadActive(unsigned tid);
+    bool isThreadSuspended(unsigned tid);
+    void addToCurrentThreads(unsigned tid);
+    void removeFromCurrentThreads(unsigned tid);
+
+  private:
+    /** The activity recorder; used to tell if the CPU has any
+     * activity remaining or if it can go to idle and deschedule
+     * itself.
+     */
+    ActivityRecorder activityRec;
+
+  public:
+    void readFunctional(Addr addr, uint32_t &buffer);
+
+    /** Number of Active Threads in the CPU */
+    int numActiveThreads() { return activeThreads.size(); }
+
+    /** Records that there was time buffer activity this cycle. */
+    void activityThisCycle() { activityRec.activity(); }
+
+    /** Changes a stage's status to active within the activity recorder. */
+    void activateStage(const int idx)
+    { activityRec.activateStage(idx); }
+
+    /** Changes a stage's status to inactive within the activity recorder. */
+    void deactivateStage(const int idx)
+    { activityRec.deactivateStage(idx); }
+
+    /** Wakes the CPU, rescheduling the CPU if it's not already active. */
+    void wakeCPU();
+
+    /** Gets a free thread id. Use if thread ids change across system. */
+    int getFreeTid();
+
+    // LL/SC debug functionality
+    unsigned stCondFails;
+    unsigned readStCondFailures() { return stCondFails; }
+    unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; }
+
+  public:
+    /** Returns a pointer to a thread context. */
+    ThreadContext *tcBase(unsigned tid = 0)
+    {
+        return thread[tid]->getTC();
+    }
+
+    /** The global sequence number counter. */
+    InstSeqNum globalSeqNum[ThePipeline::MaxThreads];
+
+    /** The global event number counter. */
+    InstSeqNum cpuEventNum;
+
+    /** Counter of how many stages have completed switching out. */
+    int switchCount;
+
+    /** Pointers to all of the threads in the CPU. */
+    std::vector<Thread *> thread;
+
+    /** Pointer to the icache interface. */
+    MemInterface *icacheInterface;
+    /** Pointer to the dcache interface. */
+    MemInterface *dcacheInterface;
+
+    /** Whether or not the CPU should defer its registration. */
+    bool deferRegistration;
+
+    /** Per-Stage Instruction Tracing */
+    bool stageTracing;
+
+    /** Is there a context switch pending? */
+    bool contextSwitch;
+
+    /** Threads Scheduled to Enter CPU */
+    std::list<int> cpuWaitList;
+
+    /** The cycle that the CPU was last running, used for statistics. */
+    Tick lastRunningCycle;
+
+    /** Number of Threads the CPU can process */
+    unsigned numThreads;
+
+    /** Number of Virtual Processors the CPU can process */
+    unsigned numVirtProcs;
+
+    /** Update Thread , used for statistic purposes*/
+    inline void tickThreadStats();
+
+    /** Per-Thread Tick */
+    Stats::Vector<> threadCycles;
+
+    /** Tick for SMT */
+    Stats::Scalar<> smtCycles;
+
+    /** Stat for total number of times the CPU is descheduled. */
+    Stats::Scalar<> timesIdled;
+
+    /** Stat for total number of cycles the CPU spends descheduled. */
+    Stats::Scalar<> idleCycles;
+
+    /** Stat for the number of committed instructions per thread. */
+    Stats::Vector<> committedInsts;
+
+    /** Stat for the number of committed instructions per thread. */
+    Stats::Vector<> smtCommittedInsts;
+
+    /** Stat for the total number of committed instructions. */
+    Stats::Scalar<> totalCommittedInsts;
+
+    /** Stat for the CPI per thread. */
+    Stats::Formula cpi;
+
+    /** Stat for the SMT-CPI per thread. */
+    Stats::Formula smtCpi;
+
+    /** Stat for the total CPI. */
+    Stats::Formula totalCpi;
+
+    /** Stat for the IPC per thread. */
+    Stats::Formula ipc;
+
+    /** Stat for the total IPC. */
+    Stats::Formula smtIpc;
+
+    /** Stat for the total IPC. */
+    Stats::Formula totalIpc;
+};
+
+#endif // __CPU_O3_CPU_HH__
diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc
new file mode 100644 (file)
index 0000000..ce30f84
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include "base/str.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+#include "params/InOrderTrace.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+FirstStage::FirstStage(Params *params, unsigned stage_num)
+    : PipelineStage(params, stage_num)
+{
+    for(int tid=0; tid < this->numThreads; tid++) {
+        stageStatus[tid] = Running;
+    }
+
+    numFetchingThreads = 1;
+
+    fetchPolicy = RoundRobin;
+}
+
+void
+FirstStage::setCPU(InOrderCPU *cpu_ptr)
+{
+    cpu = cpu_ptr;
+
+    fetchPriorityList = &cpu->fetchPriorityList;
+
+    DPRINTF(InOrderStage, "Set CPU pointer.\n");
+}
+
+
+void
+FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+    // Set status to squashing.
+    //stageStatus[tid] = Squashing;
+
+    // Clear the instruction list and skid buffer in case they have any
+    // insts in them.
+    DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n");
+    while (!insts[tid].empty()) {
+        if (insts[tid].front()->seqNum <= squash_seq_num) {
+            DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= "
+                    "squashing seqNum %i.\n",
+                    tid,
+                    insts[tid].front()->seqNum,
+                    squash_seq_num);
+
+            DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming "
+                    "instructions before delay slot [sn:%i]. %i insts"
+                    "left.\n", tid, squash_seq_num,
+                    insts[tid].size());
+            break;
+        }
+        DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
+                tid, insts[tid].front()->seqNum, insts[tid].front()->PC);
+        insts[tid].pop();
+    }
+
+    // Now that squash has propagated to the first stage,
+    // Alert CPU to remove instructions from the CPU instruction list.
+    // @todo: Move this to the CPU object.
+    cpu->removeInstsUntil(squash_seq_num, tid);
+}
+
+void
+FirstStage::processStage(bool &status_change)
+{
+    list<unsigned>::iterator threads = (*activeThreads).begin();
+
+    //Check stall and squash signals.
+    while (threads != (*activeThreads).end()) {
+        unsigned tid = *threads++;
+        status_change =  checkSignalsAndUpdate(tid) || status_change;
+    }
+
+    for (int threadFetched = 0; threadFetched < numFetchingThreads;
+         threadFetched++) {
+        int tid = getFetchingThread(fetchPolicy);
+
+        if (tid >= 0) {
+            DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
+            processThread(status_change, tid);
+        } else {
+            DPRINTF(InOrderStage, "No more threads to fetch from.\n");
+        }
+    }
+}
+
+//@TODO: Note in documentation, that when you make a pipeline stage change, then
+//make sure you change the first stage too
+void
+FirstStage::processInsts(unsigned tid)
+{
+    bool all_reqs_completed = true;
+
+    for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToNextStage(); insts_fetched++) {
+        DynInstPtr inst;
+        bool new_inst = false;
+
+        if (!insts[tid].empty()) {
+            inst = insts[tid].front();
+        } else {
+            // Get new instruction.
+            new_inst = true;
+
+            inst = new InOrderDynInst(cpu,
+                                    cpu->thread[tid],
+                                    cpu->nextInstSeqNum(tid),
+                                    tid);
+
+#if TRACING_ON
+            inst->traceData =
+                tracer->getInstRecord(ThePipeline::NumStages,
+                                      cpu->stageTracing,
+                                      cpu->thread[tid]->getTC());
+
+#endif      // TRACING_ON
+
+            DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n",
+                    inst->readTid(),
+                    inst->seqNum,
+                    0/*inst->curCount()*/);
+
+            // Add instruction to the CPU's list of instructions.
+            inst->setInstListIt(cpu->addInst(inst));
+
+            DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n",
+                    inst->readTid(),
+                    inst->seqNum,
+                    0/*inst->curCount()*/);
+
+            // Create Front-End Resource Schedule For Instruction
+            ThePipeline::createFrontEndSchedule(inst);
+        }
+
+        // Don't let instruction pass to next stage if it hasnt completed
+        // all of it's requests for this stage.
+        all_reqs_completed = processInstSchedule(inst);
+
+        if (!all_reqs_completed) {
+            if (new_inst) {
+                DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all "
+                        "requests for this stage. Keep in stage inst. "
+                        "list.\n", tid, inst->seqNum);
+                insts[tid].push(inst);
+            }
+            break;
+        } else if (!insts[tid].empty()){
+            insts[tid].pop();
+        }
+
+        sendInstToNextStage(inst);
+        //++stageProcessedInsts;
+    }
+
+    // Record that stage has written to the time buffer for activity
+    // tracking.
+    if (toNextStageIndex) {
+        wroteToTimeBuffer = true;
+    }
+}
+
+int
+FirstStage::getFetchingThread(FetchPriority &fetch_priority)
+{
+    if (numThreads > 1) {
+        switch (fetch_priority) {
+
+          case SingleThread:
+            return 0;
+
+          case RoundRobin:
+            return roundRobin();
+
+          default:
+            return -1;
+        }
+    } else {
+        int tid = *((*activeThreads).begin());
+
+        if (stageStatus[tid] == Running ||
+            stageStatus[tid] == Idle) {
+            return tid;
+        } else {
+            return -1;
+        }
+    }
+
+}
+
+int
+FirstStage::roundRobin()
+{
+    list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin();
+    list<unsigned>::iterator end      = (*fetchPriorityList).end();
+
+    int high_pri;
+
+    while (pri_iter != end) {
+        high_pri = *pri_iter;
+
+        assert(high_pri <= numThreads);
+
+        if (stageStatus[high_pri] == Running ||
+            stageStatus[high_pri] == Idle) {
+
+            (*fetchPriorityList).erase(pri_iter);
+            (*fetchPriorityList).push_back(high_pri);
+
+            return high_pri;
+        }
+
+        pri_iter++;
+    }
+
+    return -1;
+}
diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh
new file mode 100644 (file)
index 0000000..55914c8
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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_FIRST_STAGE_HH__
+#define __CPU_INORDER_FIRST_STAGE_HH__
+
+#include <queue>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/comm.hh"
+#include "cpu/inorder/params.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/pipeline_stage.hh"
+
+class InOrderCPU;
+
+class FirstStage : public PipelineStage {
+  public:
+    FirstStage(ThePipeline::Params *params, unsigned stage_num);
+
+    /** Set Pointer to CPU */
+    void setCPU(InOrderCPU *cpu_ptr);
+
+    /** Evaluate Stage Info. & Execute Stage */
+    void processStage(bool &status_change);
+
+    /** Process All Instructions Available */
+    void processInsts(unsigned tid);
+
+    /** Squash Instructions Above a Seq. Num */
+    void squash(InstSeqNum squash_seq_num, unsigned tid);
+
+    /** There are no insts. coming from previous stages, so there is
+     * no need to sort insts here
+     */
+    void sortInsts() {}
+
+    /** There are no skidBuffers for the first stage. So
+     *  just use an empty function.
+     */
+    void skidInsert(unsigned tid) { }
+
+    /** The number of fetching threads in the CPU */
+    int numFetchingThreads;
+
+    //@TODO: Add fetch priority information to a resource class...
+    /** Fetching Policy, Add new policies here.*/
+    enum FetchPriority {
+        SingleThread,
+        RoundRobin
+    };
+
+    /** Fetch policy. */
+    FetchPriority fetchPolicy;
+
+    /** List that has the threads organized by priority. */
+    std::list<unsigned> *fetchPriorityList;
+
+    /** Return the next fetching thread */
+    int getFetchingThread(FetchPriority &fetch_priority);
+
+    /** Return next thred given Round Robin Policy for Thread Fetching */
+    int roundRobin();
+};
+
+#endif // __CPU_INORDER_FIRST_STAGE_HH__
diff --git a/src/cpu/inorder/inorder_cpu_builder.cc b/src/cpu/inorder/inorder_cpu_builder.cc
new file mode 100644 (file)
index 0000000..b1b4bea
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 <string>
+
+#include "cpu/base.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/cpu.hh"
+//#include "cpu/inorder/params.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "params/InOrderCPU.hh"
+
+InOrderCPU *
+InOrderCPUParams::create()
+{
+    int actual_num_threads =
+        (numThreads >= workload.size()) ? numThreads : workload.size();
+
+    if (workload.size() == 0) {
+        fatal("Must specify at least one workload!");
+    }
+
+    numThreads = actual_num_threads;
+
+    instShiftAmt = 2;
+
+    return new InOrderCPU(this);
+}
+
+
+
diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc
new file mode 100644 (file)
index 0000000..89362c6
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * 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 <iostream>
+#include <set>
+#include <string>
+#include <sstream>
+
+#include "base/cprintf.hh"
+#include "base/trace.hh"
+
+#include "arch/faults.hh"
+#include "cpu/exetrace.hh"
+#include "mem/request.hh"
+
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC,
+                               Addr pred_PC, InstSeqNum seq_num,
+                               InOrderCPU *cpu)
+  : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu)
+{
+    seqNum = seq_num;
+
+    PC = inst_PC;
+    nextPC = PC + sizeof(MachInst);
+    nextNPC = nextPC + sizeof(MachInst);
+    predPC = pred_PC;
+
+    initVars();
+}
+
+InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
+                           InOrderThreadState *state,
+                           InstSeqNum seq_num,
+                           unsigned tid)
+    : traceData(NULL), cpu(cpu)
+{
+    seqNum = seq_num;
+    thread = state;
+    threadNumber = tid;
+    initVars();
+}
+
+InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst)
+    : staticInst(_staticInst), traceData(NULL)
+{
+    seqNum = 0;
+    initVars();
+}
+
+InOrderDynInst::InOrderDynInst()
+    : traceData(NULL), cpu(cpu)
+{     initVars(); }
+
+int InOrderDynInst::instcount = 0;
+
+
+void
+InOrderDynInst::setMachInst(ExtMachInst machInst)
+{
+    staticInst = StaticInst::decode(machInst, PC);
+
+    for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
+        _destRegIdx[i] = this->staticInst->destRegIdx(i);
+    }
+
+    for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
+        _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+        this->_readySrcRegIdx[i] = 0;
+    }
+}
+
+void
+InOrderDynInst::initVars()
+{
+    req = NULL;
+    effAddr = 0;
+    physEffAddr = 0;
+
+    readyRegs = 0;
+
+    nextStage = 0;
+    nextInstStageNum = 0;
+
+    for(int i = 0; i < MaxInstDestRegs; i++)
+        instResult[i].val.integer = 0;
+
+    status.reset();
+
+    memAddrReady = false;
+    eaCalcDone = false;
+    memOpDone = false;
+
+    predictTaken = false;
+    procDelaySlotOnMispred = false;
+
+    lqIdx = -1;
+    sqIdx = -1;
+
+    // Also make this a parameter, or perhaps get it from xc or cpu.
+    asid = 0;
+
+    virtProcNumber = 0;
+
+    // Initialize the fault to be NoFault.
+    fault = NoFault;
+
+    // Make sure to have the renamed register entries set to the same
+    // as the normal register entries.  It will allow the IQ to work
+    // without any modifications.
+    if (this->staticInst) {
+        for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
+            _destRegIdx[i] = this->staticInst->destRegIdx(i);
+        }
+
+        for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
+            _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+            this->_readySrcRegIdx[i] = 0;
+        }
+    }
+
+    // Update Instruction Count for this instruction
+    ++instcount;
+    if (instcount > 500) {
+        fatal("Number of Active Instructions in CPU is too high. "
+                "(Not Dereferencing Ptrs. Correctly?)\n");
+    }
+
+
+
+    DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n",
+            threadNumber, seqNum, instcount);
+
+#ifdef DEBUG
+    cpu->snList.insert(seqNum);
+#endif
+}
+
+
+InOrderDynInst::~InOrderDynInst()
+{
+    if (req) {
+        delete req;
+    }
+
+    if (traceData) {
+        delete traceData;
+    }
+
+    fault = NoFault;
+
+    --instcount;
+
+    deleteStages();
+
+    DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n",
+            threadNumber, seqNum, instcount);
+#ifdef DEBUG
+    cpu->snList.erase(seqNum);
+#endif
+}
+
+void
+InOrderDynInst::setStaticInst(StaticInstPtr &static_inst)
+{
+    this->staticInst = static_inst;
+
+    // Make sure to have the renamed register entries set to the same
+    // as the normal register entries.  It will allow the IQ to work
+    // without any modifications.
+    if (this->staticInst) {
+        for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
+            _destRegIdx[i] = this->staticInst->destRegIdx(i);
+        }
+
+        for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
+            _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+            this->_readySrcRegIdx[i] = 0;
+        }
+    }
+}
+
+Fault
+InOrderDynInst::execute()
+{
+    // @todo: Pretty convoluted way to avoid squashing from happening
+    // when using the TC during an instruction's execution
+    // (specifically for instructions that have side-effects that use
+    // the TC).  Fix this.
+    bool in_syscall = this->thread->inSyscall;
+    this->thread->inSyscall = true;
+
+    this->fault = this->staticInst->execute(this, this->traceData);
+
+    this->thread->inSyscall = in_syscall;
+
+    return this->fault;
+}
+
+Fault
+InOrderDynInst::initiateAcc()
+{
+    // @todo: Pretty convoluted way to avoid squashing from happening
+    // when using the TC during an instruction's execution
+    // (specifically for instructions that have side-effects that use
+    // the TC).  Fix this.
+    bool in_syscall = this->thread->inSyscall;
+    this->thread->inSyscall = true;
+
+    this->fault = this->staticInst->initiateAcc(this, this->traceData);
+
+    this->thread->inSyscall = in_syscall;
+
+    return this->fault;
+}
+
+
+Fault
+InOrderDynInst::completeAcc(Packet *pkt)
+{
+    this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
+
+    return this->fault;
+}
+
+InstStage *InOrderDynInst::addStage()
+{
+    this->currentInstStage = new InstStage(this, nextInstStageNum++);
+    instStageList.push_back( this->currentInstStage );
+    return this->currentInstStage;
+}
+
+InstStage *InOrderDynInst::addStage(int stage_num)
+{
+    nextInstStageNum = stage_num;
+    return InOrderDynInst::addStage();
+}
+
+void InOrderDynInst::deleteStages() {
+    std::list<InstStage*>::iterator list_it = instStageList.begin();
+    std::list<InstStage*>::iterator list_end = instStageList.end();
+
+    while(list_it != list_end) {
+        delete *list_it;
+        list_it++;
+    }
+}
+
+Fault
+InOrderDynInst::calcEA()
+{
+    return staticInst->eaCompInst()->execute(this, this->traceData);
+}
+
+Fault
+InOrderDynInst::memAccess()
+{
+    //return staticInst->memAccInst()->execute(this, this->traceData);
+    return initiateAcc( );
+}
+
+void
+InOrderDynInst::syscall(int64_t callnum)
+{
+    cpu->syscall(callnum, this->threadNumber);
+}
+
+void
+InOrderDynInst::prefetch(Addr addr, unsigned flags)
+{
+    // This is the "functional" implementation of prefetch.  Not much
+    // happens here since prefetches don't affect the architectural
+    // state.
+/*
+    // Generate a MemReq so we can translate the effective address.
+    MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags);
+    req->asid = asid;
+
+    // Prefetches never cause faults.
+    fault = NoFault;
+
+    // note this is a local, not InOrderDynInst::fault
+    Fault trans_fault = cpu->translateDataReadReq(req);
+
+    if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) {
+        // It's a valid address to cacheable space.  Record key MemReq
+        // parameters so we can generate another one just like it for
+        // the timing access without calling translate() again (which
+        // might mess up the TLB).
+        effAddr = req->vaddr;
+        physEffAddr = req->paddr;
+        memReqFlags = req->flags;
+    } else {
+        // Bogus address (invalid or uncacheable space).  Mark it by
+        // setting the eff_addr to InvalidAddr.
+        effAddr = physEffAddr = MemReq::inval_addr;
+    }
+
+    if (traceData) {
+        traceData->setAddr(addr);
+    }
+*/
+}
+
+void
+InOrderDynInst::writeHint(Addr addr, int size, unsigned flags)
+{
+    // Not currently supported.
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+Fault
+InOrderDynInst::copySrcTranslate(Addr src)
+{
+    // Not currently supported.
+    return NoFault;
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+Fault
+InOrderDynInst::copy(Addr dest)
+{
+    // Not currently supported.
+    return NoFault;
+}
+
+void
+InOrderDynInst::releaseReq(ResourceRequest* req)
+{
+    std::list<ResourceRequest*>::iterator list_it = reqList.begin();
+    std::list<ResourceRequest*>::iterator list_end = reqList.end();
+
+    while(list_it != list_end) {
+        if((*list_it)->getResIdx() == req->getResIdx() &&
+           (*list_it)->getSlot() == req->getSlot()) {
+            DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n",
+                    threadNumber, seqNum, req->res->name());
+            reqList.erase(list_it);
+            return;
+        }
+        list_it++;
+    }
+
+    panic("Releasing Res. Request That Isnt There!\n");
+}
+
+/** Records an integer source register being set to a value. */
+void
+InOrderDynInst::setIntSrc(int idx, uint64_t val)
+{
+    DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n",
+            threadNumber, seqNum, idx, val);
+    instSrc[idx].integer = val;
+}
+
+/** Records an fp register being set to a value. */
+void
+InOrderDynInst::setFloatSrc(int idx, FloatReg val, int width)
+{
+    if (width == 32)
+        instSrc[idx].fp = val;
+    else if (width == 64)
+        instSrc[idx].dbl = val;
+    else
+        panic("Unsupported width!");
+}
+
+/** Records an fp register being set to an integer value. */
+void
+InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val)
+{
+    instSrc[idx].integer = val;
+}
+
+/** Reads a integer register. */
+IntReg
+InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, unsigned tid)
+{
+    DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
+            threadNumber, seqNum, idx, instSrc[idx].integer);
+    return instSrc[idx].integer;
+}
+
+/** Reads a FP register. */
+FloatReg
+InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx, int width)
+{
+   return instSrc[idx].fp;
+}
+
+
+/** Reads a FP register as a integer. */
+FloatRegBits
+InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx, int width)
+{
+    return instSrc[idx].integer;
+}
+
+/** Reads a miscellaneous register. */
+MiscReg
+InOrderDynInst::readMiscReg(int misc_reg)
+{
+    return this->cpu->readMiscReg(misc_reg, threadNumber);
+}
+
+/** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+MiscReg
+InOrderDynInst::readMiscRegNoEffect(int misc_reg)
+{
+    return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber);
+}
+
+/** Reads a miscellaneous register. */
+MiscReg
+InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx)
+{
+    return this->cpu->readMiscRegNoEffect(
+        si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+        this->threadNumber);
+}
+
+/** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+MiscReg
+InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx)
+{
+    return this->cpu->readMiscReg(
+        si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+        this->threadNumber);
+}
+
+/** Sets a misc. register. */
+void
+InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
+{
+    instResult[si->destRegIdx(idx)].val.integer = val;
+    instResult[si->destRegIdx(idx)].tick = curTick;
+
+    this->cpu->setMiscRegNoEffect(
+        si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+        val, this->threadNumber);
+}
+
+/** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
+void
+InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
+                       const MiscReg &val)
+{
+    instResult[si->destRegIdx(idx)].val.integer = val;
+    instResult[si->destRegIdx(idx)].tick = curTick;
+
+    this->cpu->setMiscReg(
+        si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+        val, this->threadNumber);
+}
+
+MiscReg
+InOrderDynInst::readRegOtherThread(unsigned reg_idx, int tid)
+{
+    if (tid == -1) {
+        tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
+    }
+
+    if (reg_idx < FP_Base_DepTag) {                   // Integer Register File
+        return this->cpu->readIntReg(reg_idx, tid);
+    } else if (reg_idx < Ctrl_Base_DepTag) {          // Float Register File
+        reg_idx -= FP_Base_DepTag;
+        return this->cpu->readFloatRegBits(reg_idx, tid);
+    } else {
+        reg_idx -= Ctrl_Base_DepTag;
+        return this->cpu->readMiscReg(reg_idx, tid);  // Misc. Register File
+    }
+}
+
+/** Sets a Integer register. */
+void
+InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val)
+{
+    instResult[idx].val.integer = val;
+    instResult[idx].tick = curTick;
+}
+
+/** Sets a FP register. */
+void
+InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width)
+{
+    if (width == 32)
+        instResult[idx].val.fp = val;
+    else if (width == 64)
+        instResult[idx].val.dbl = val;
+    else
+        panic("Unsupported Floating Point Width!");
+
+    instResult[idx].tick = curTick;
+}
+
+/** Sets a FP register as a integer. */
+void
+InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
+                              FloatRegBits val, int width)
+{
+    instResult[idx].val.integer = val;
+    instResult[idx].tick = curTick;
+}
+
+/** Sets a misc. register. */
+/* Alter this when wanting to *speculate* on Miscellaneous registers */
+void
+InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+{
+    this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber);
+}
+
+/** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
+/* Alter this if/when wanting to *speculate* on Miscellaneous registers */
+void
+InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
+{
+    this->cpu->setMiscReg(misc_reg, val, threadNumber);
+}
+
+void
+InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val, int tid)
+{
+    if (tid == -1) {
+        tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
+    }
+
+    if (reg_idx < FP_Base_DepTag) {            // Integer Register File
+        this->cpu->setIntReg(reg_idx, val, tid);
+    } else if (reg_idx < Ctrl_Base_DepTag) {   // Float Register File
+        reg_idx -= FP_Base_DepTag;
+        this->cpu->setFloatRegBits(reg_idx, val, tid);
+    } else {
+        reg_idx -= Ctrl_Base_DepTag;
+        this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File
+    }
+}
+
+void
+InOrderDynInst::deallocateContext(int thread_num)
+{
+    this->cpu->deallocateContext(thread_num);
+}
+
+void
+InOrderDynInst::enableVirtProcElement(unsigned vpe)
+{
+    this->cpu->enableVirtProcElement(vpe);
+}
+
+void
+InOrderDynInst::disableVirtProcElement(unsigned vpe)
+{
+    this->cpu->disableVirtProcElement(threadNumber, vpe);
+}
+
+void
+InOrderDynInst::enableMultiThreading(unsigned vpe)
+{
+    this->cpu->enableMultiThreading(vpe);
+}
+
+void
+InOrderDynInst::disableMultiThreading(unsigned vpe)
+{
+    this->cpu->disableMultiThreading(threadNumber, vpe);
+}
+
+void
+InOrderDynInst::setThreadRescheduleCondition(uint32_t cond)
+{
+    this->cpu->setThreadRescheduleCondition(cond);
+}
+
+template<class T>
+inline Fault
+InOrderDynInst::read(Addr addr, T &data, unsigned flags)
+{
+    return cpu->read(this);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags);
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags);
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags);
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+InOrderDynInst::read(Addr addr, double &data, unsigned flags)
+{
+    return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+InOrderDynInst::read(Addr addr, float &data, unsigned flags)
+{
+    return read(addr, *(uint32_t*)&data, flags);
+}
+
+template<>
+Fault
+InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags)
+{
+    return read(addr, (uint32_t&)data, flags);
+}
+
+template<class T>
+inline Fault
+InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+    //memcpy(memData, gtoh(data), sizeof(T));
+    storeData  = data;
+
+    DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n",
+            threadNumber, seqNum, memData);
+    return cpu->write(this);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+InOrderDynInst::write(uint64_t data, Addr addr,
+                       unsigned flags, uint64_t *res);
+
+template
+Fault
+InOrderDynInst::write(uint32_t data, Addr addr,
+                       unsigned flags, uint64_t *res);
+
+template
+Fault
+InOrderDynInst::write(uint16_t data, Addr addr,
+                       unsigned flags, uint64_t *res);
+
+template
+Fault
+InOrderDynInst::write(uint8_t data, Addr addr,
+                       unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+    return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+    return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+
+template<>
+Fault
+InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+    return write((uint32_t)data, addr, flags, res);
+}
+
+
+void
+InOrderDynInst::dump()
+{
+    cprintf("T%d : %#08d `", threadNumber, PC);
+    cout << staticInst->disassemble(PC);
+    cprintf("'\n");
+}
+
+void
+InOrderDynInst::dump(std::string &outstring)
+{
+    std::ostringstream s;
+    s << "T" << threadNumber << " : 0x" << PC << " "
+      << staticInst->disassemble(PC);
+
+    outstring = s.str();
+}
+
+
+#define NOHASH
+#ifndef NOHASH
+
+#include "base/hashmap.hh"
+
+unsigned int MyHashFunc(const InOrderDynInst *addr)
+{
+    unsigned a = (unsigned)addr;
+    unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
+
+    return hash;
+}
+
+typedef m5::hash_map<const InOrderDynInst *, const InOrderDynInst *, MyHashFunc>
+my_hash_t;
+
+my_hash_t thishash;
+#endif
+
+#ifdef DEBUG
+
+void
+InOrderDynInst::dumpSNList()
+{
+    std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin();
+
+    int count = 0;
+    while (sn_it != cpu->snList.end()) {
+        cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it));
+        count++;
+        sn_it++;
+    }
+}
+#endif
+
diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh
new file mode 100644 (file)
index 0000000..9f52f95
--- /dev/null
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * Copyright (c) 2004-2006 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_DYN_INST_HH__
+#define __CPU_INORDER_DYN_INST_HH__
+
+#include <bitset>
+#include <list>
+#include <string>
+
+#include "arch/faults.hh"
+#include "base/fast_alloc.hh"
+#include "base/trace.hh"
+#include "cpu/inorder/inorder_trace.hh"
+#include "config/full_system.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/op_class.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "mem/packet.hh"
+#include "sim/system.hh"
+
+/**
+ * @file
+ * Defines a dynamic instruction context for a inorder CPU model.
+ */
+
+// Forward declaration.
+class StaticInstPtr;
+class ResourceRequest;
+
+class InOrderDynInst : public FastAlloc, public RefCounted
+{
+  public:
+    // Binary machine instruction type.
+    typedef TheISA::MachInst MachInst;
+    // Extended machine instruction type
+    typedef TheISA::ExtMachInst ExtMachInst;
+    // Logical register index type.
+    typedef TheISA::RegIndex RegIndex;
+    // Integer register type.
+    typedef TheISA::IntReg IntReg;
+    // Floating point register type.
+    typedef TheISA::FloatReg FloatReg;
+    // Floating point register type.
+    typedef TheISA::MiscReg MiscReg;
+
+    typedef short int PhysRegIndex;
+
+    /** The refcounted DynInst pointer to be used.  In most cases this is
+     *  what should be used, and not DynInst*.
+     */
+    typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+    // The list of instructions iterator type.
+    typedef std::list<DynInstPtr>::iterator ListIt;
+
+    enum {
+        MaxInstSrcRegs = TheISA::MaxInstSrcRegs,       /// Max source regs
+        MaxInstDestRegs = TheISA::MaxInstDestRegs,     /// Max dest regs
+    };
+
+  public:
+    /** BaseDynInst constructor given a binary instruction.
+     *  @param inst The binary instruction.
+     *  @param PC The PC of the instruction.
+     *  @param pred_PC The predicted next PC.
+     *  @param seq_num The sequence number of the instruction.
+     *  @param cpu Pointer to the instruction's CPU.
+     */
+    InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num,
+                 InOrderCPU *cpu);
+
+    /** BaseDynInst constructor given a binary instruction.
+     *  @param seq_num The sequence number of the instruction.
+     *  @param cpu Pointer to the instruction's CPU.
+     *  NOTE: Must set Binary Instrution through Member Function
+     */
+    InOrderDynInst(InOrderCPU *cpu, InOrderThreadState *state, InstSeqNum seq_num,
+                 unsigned tid);
+
+    /** BaseDynInst constructor given a StaticInst pointer.
+     *  @param _staticInst The StaticInst for this BaseDynInst.
+     */
+    InOrderDynInst(StaticInstPtr &_staticInst);
+
+    /** Skeleton Constructor. */
+    InOrderDynInst();
+
+    /** InOrderDynInst destructor. */
+    ~InOrderDynInst();
+
+  public:
+    /** The sequence number of the instruction. */
+    InstSeqNum seqNum;
+
+    /** The sequence number of the instruction. */
+    InstSeqNum bdelaySeqNum;
+
+    enum Status {
+        RegDepMapEntry,          /// Instruction has been entered onto the RegDepMap
+        IqEntry,                 /// Instruction is in the IQ
+        RobEntry,                /// Instruction is in the ROB
+        LsqEntry,                /// Instruction is in the LSQ
+        Completed,               /// Instruction has completed
+        ResultReady,             /// Instruction has its result
+        CanIssue,                /// Instruction can issue and execute
+        Issued,                  /// Instruction has issued
+        Executed,                /// Instruction has executed
+        CanCommit,               /// Instruction can commit
+        AtCommit,                /// Instruction has reached commit
+        Committed,               /// Instruction has committed
+        Squashed,                /// Instruction is squashed
+        SquashedInIQ,            /// Instruction is squashed in the IQ
+        SquashedInLSQ,           /// Instruction is squashed in the LSQ
+        SquashedInROB,           /// Instruction is squashed in the ROB
+        RecoverInst,             /// Is a recover instruction
+        BlockingInst,            /// Is a blocking instruction
+        ThreadsyncWait,          /// Is a thread synchronization instruction
+        SerializeBefore,         /// Needs to serialize on
+                                 /// instructions ahead of it
+        SerializeAfter,          /// Needs to serialize instructions behind it
+        SerializeHandled,        /// Serialization has been handled
+        NumStatus
+    };
+
+    /** The status of this BaseDynInst.  Several bits can be set. */
+    std::bitset<NumStatus> status;
+
+    /** The thread this instruction is from. */
+    short threadNumber;
+
+    /** data address space ID, for loads & stores. */
+    short asid;
+
+    /** The virtual processor number */
+    short virtProcNumber;
+
+    /** The StaticInst used by this BaseDynInst. */
+    StaticInstPtr staticInst;
+
+    /** InstRecord that tracks this instructions. */
+    Trace::InOrderTraceRecord *traceData;
+
+    /** Pointer to the Impl's CPU object. */
+    InOrderCPU *cpu;
+
+    /** Pointer to the thread state. */
+    InOrderThreadState *thread;
+
+    /** The kind of fault this instruction has generated. */
+    Fault fault;
+
+    /** The memory request. */
+    Request *req;
+
+    /** Pointer to the data for the memory access. */
+    uint8_t *memData;
+
+    /**  Data used for a store for operation. */
+    uint64_t loadData;
+
+    /**  Data used for a store for operation. */
+    uint64_t storeData;
+
+    /** The resource schedule for this inst */
+    ThePipeline::ResSchedule resSched;
+
+    /** List of active resource requests for this instruction */
+    std::list<ResourceRequest*> reqList;
+
+    /** The effective virtual address (lds & stores only). */
+    Addr effAddr;
+
+    /** The effective physical address. */
+    Addr physEffAddr;
+
+    /** Effective virtual address for a copy source. */
+    Addr copySrcEffAddr;
+
+    /** Effective physical address for a copy source. */
+    Addr copySrcPhysEffAddr;
+
+    /** The memory request flags (from translation). */
+    unsigned memReqFlags;
+
+    /** How many source registers are ready. */
+    unsigned readyRegs;
+
+    /** An instruction src/dest has to be one of these types */
+    union InstValue {
+        uint64_t integer;
+        float fp;
+        double dbl;
+    };
+
+    /** Result of an instruction execution */
+    struct InstResult {
+        InstValue val;
+        Tick tick;
+    };
+
+    /** The source of the instruction; assumes for now that there's only one
+     *  destination register.
+     */
+    InstValue instSrc[MaxInstSrcRegs];
+
+    /** The result of the instruction; assumes for now that there's only one
+     *  destination register.
+     */
+    InstResult instResult[MaxInstDestRegs];
+
+    /** PC of this instruction. */
+    Addr PC;
+
+    /** Next non-speculative PC.  It is not filled in at fetch, but rather
+     *  once the target of the branch is truly known (either decode or
+     *  execute).
+     */
+    Addr nextPC;
+
+    /** Next next non-speculative PC.  It is not filled in at fetch, but rather
+     *  once the target of the branch is truly known (either decode or
+     *  execute).
+     */
+    Addr nextNPC;
+
+    /** Predicted next PC. */
+    Addr predPC;
+
+    /** Address to fetch from */
+    Addr fetchAddr;
+
+    /** Address to get/write data from/to */
+    Addr memAddr;
+
+    /** Whether or not the source register is ready.
+     *  @todo: Not sure this should be here vs the derived class.
+     */
+    bool _readySrcRegIdx[MaxInstSrcRegs];
+
+    /** Physical register index of the destination registers of this
+     *  instruction.
+     */
+    PhysRegIndex _destRegIdx[MaxInstDestRegs];
+
+    /** Physical register index of the source registers of this
+     *  instruction.
+     */
+    PhysRegIndex _srcRegIdx[MaxInstSrcRegs];
+
+    /** Physical register index of the previous producers of the
+     *  architected destinations.
+     */
+    PhysRegIndex _prevDestRegIdx[MaxInstDestRegs];
+
+    int nextStage;
+
+    /* vars to keep track of InstStage's - used for resource sched defn */
+    int nextInstStageNum;
+    ThePipeline::InstStage *currentInstStage;
+    std::list<ThePipeline::InstStage*> instStageList;
+
+  private:
+    /** Function to initialize variables in the constructors. */
+    void initVars();
+
+  public:
+    Tick memTime;
+
+    ////////////////////////////////////////////////////////////
+    //
+    //  BASE INSTRUCTION INFORMATION.
+    //
+    ////////////////////////////////////////////////////////////
+    void setMachInst(ExtMachInst inst);
+
+    /** Sets the StaticInst. */
+    void setStaticInst(StaticInstPtr &static_inst);
+
+    /** Sets the sequence number. */
+    void setSeqNum(InstSeqNum seq_num) { seqNum = seq_num; }
+
+    /** Sets the ASID. */
+    void setASID(short addr_space_id) { asid = addr_space_id; }
+
+    /** Reads the thread id. */
+    short readTid() { return threadNumber; }
+
+    /** Sets the thread id. */
+    void setTid(unsigned tid) { threadNumber = tid; }
+
+    void setVpn(int id) { virtProcNumber = id; }
+
+    int readVpn() { return virtProcNumber; }
+
+    /** Sets the pointer to the thread state. */
+    void setThreadState(InOrderThreadState *state) { thread = state; }
+
+    /** Returns the thread context. */
+    ThreadContext *tcBase() { return thread->getTC(); }
+
+    /** Returns the fault type. */
+    Fault getFault() { return fault; }
+
+    ////////////////////////////////////////////////////////////
+    //
+    //  INSTRUCTION TYPES -  Forward checks to StaticInst object.
+    //
+    ////////////////////////////////////////////////////////////
+    bool isNop()         const { return staticInst->isNop(); }
+    bool isMemRef()              const { return staticInst->isMemRef(); }
+    bool isLoad()        const { return staticInst->isLoad(); }
+    bool isStore()       const { return staticInst->isStore(); }
+    bool isStoreConditional() const
+    { return staticInst->isStoreConditional(); }
+    bool isInstPrefetch() const { return staticInst->isInstPrefetch(); }
+    bool isDataPrefetch() const { return staticInst->isDataPrefetch(); }
+    bool isCopy()         const { return staticInst->isCopy(); }
+    bool isInteger()     const { return staticInst->isInteger(); }
+    bool isFloating()    const { return staticInst->isFloating(); }
+    bool isControl()     const { return staticInst->isControl(); }
+    bool isCall()        const { return staticInst->isCall(); }
+    bool isReturn()      const { return staticInst->isReturn(); }
+    bool isDirectCtrl()          const { return staticInst->isDirectCtrl(); }
+    bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); }
+    bool isCondCtrl()    const { return staticInst->isCondCtrl(); }
+    bool isUncondCtrl()          const { return staticInst->isUncondCtrl(); }
+    bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); }
+
+    bool isThreadSync()   const { return staticInst->isThreadSync(); }
+    bool isSerializing()  const { return staticInst->isSerializing(); }
+    bool isSerializeBefore() const
+    { return staticInst->isSerializeBefore() || status[SerializeBefore]; }
+    bool isSerializeAfter() const
+    { return staticInst->isSerializeAfter() || status[SerializeAfter]; }
+    bool isMemBarrier()   const { return staticInst->isMemBarrier(); }
+    bool isWriteBarrier() const { return staticInst->isWriteBarrier(); }
+    bool isNonSpeculative() const { return staticInst->isNonSpeculative(); }
+    bool isQuiesce() const { return staticInst->isQuiesce(); }
+    bool isIprAccess() const { return staticInst->isIprAccess(); }
+    bool isUnverifiable() const { return staticInst->isUnverifiable(); }
+
+    /////////////////////////////////////////////
+    //
+    // RESOURCE SCHEDULING
+    //
+    /////////////////////////////////////////////
+
+    void setNextStage(int stage_num) { nextStage = stage_num; }
+    int getNextStage() { return nextStage; }
+
+    ThePipeline::InstStage *addStage();
+    ThePipeline::InstStage *addStage(int stage);
+    ThePipeline::InstStage *currentStage() { return currentInstStage; }
+    void deleteStages();
+
+    /** Add A Entry To Reource Schedule */
+    void addToSched(ThePipeline::ScheduleEntry* sched_entry)
+    { resSched.push(sched_entry); }
+
+
+    /** Print Resource Schedule */
+    void printSched()
+    {
+        using namespace ThePipeline;
+
+        ResSchedule tempSched;
+        std::cerr << "\tInst. Res. Schedule: ";
+        while (!resSched.empty()) {
+            std::cerr << '\t' << resSched.top()->stageNum << "-"
+                 << resSched.top()->resNum << ", ";
+
+            tempSched.push(resSched.top());
+            resSched.pop();
+        }
+
+        std::cerr << std::endl;
+        resSched = tempSched;
+    }
+
+    /** Return Next Resource Stage To Be Used */
+    int nextResStage()
+    {
+        if (resSched.empty())
+            return -1;
+        else
+            return resSched.top()->stageNum;
+    }
+
+
+    /** Return Next Resource To Be Used */
+    int nextResource()
+    {
+        if (resSched.empty())
+            return -1;
+        else
+            return resSched.top()->resNum;
+    }
+
+    /** Remove & Deallocate a schedule entry */
+    void popSchedEntry()
+    {
+        if (!resSched.empty()) {
+            ThePipeline::ScheduleEntry* sked = resSched.top();
+            resSched.pop();
+            delete sked;
+        }
+    }
+
+    /** Release a Resource Request (Currently Unused) */
+    void releaseReq(ResourceRequest* req);
+
+    ////////////////////////////////////////////
+    //
+    // INSTRUCTION EXECUTION
+    //
+    ////////////////////////////////////////////
+    /** Returns the opclass of this instruction. */
+    OpClass opClass() const { return staticInst->opClass(); }
+
+    /** Executes the instruction.*/
+    Fault execute();
+
+    unsigned curResSlot;
+
+    unsigned getCurResSlot() { return curResSlot; }
+
+    void setCurResSlot(unsigned slot_num) { curResSlot = slot_num; }
+
+    /** Calls a syscall. */
+    void syscall(int64_t callnum);
+    void prefetch(Addr addr, unsigned flags);
+    void writeHint(Addr addr, int size, unsigned flags);
+    Fault copySrcTranslate(Addr src);
+    Fault copy(Addr dest);
+
+    ////////////////////////////////////////////////////////////
+    //
+    // MULTITHREADING INTERFACE TO CPU MODELS
+    //
+    ////////////////////////////////////////////////////////////
+    virtual void deallocateContext(int thread_num);
+
+    virtual void enableVirtProcElement(unsigned vpe);
+    virtual void disableVirtProcElement(unsigned vpe);
+
+    virtual void enableMultiThreading(unsigned vpe);
+    virtual void disableMultiThreading(unsigned vpe);
+
+    virtual void setThreadRescheduleCondition(uint32_t cond);
+
+    ////////////////////////////////////////////////////////////
+    //
+    //  PROGRAM COUNTERS - PC/NPC/NPC
+    //
+    ////////////////////////////////////////////////////////////
+    /** Read the PC of this instruction. */
+    const Addr readPC() const { return PC; }
+
+    /** Sets the PC of this instruction. */
+    void setPC(Addr pc) { PC = pc; }
+
+    /** Returns the next PC.  This could be the speculative next PC if it is
+     *  called prior to the actual branch target being calculated.
+     */
+    Addr readNextPC() { return nextPC; }
+
+    /** Set the next PC of this instruction (its actual target). */
+    void setNextPC(uint64_t val) { nextPC = val; }
+
+    /** Returns the next NPC.  This could be the speculative next NPC if it is
+     *  called prior to the actual branch target being calculated.
+     */
+    Addr readNextNPC() { return nextNPC; }
+
+    /** Set the next PC of this instruction (its actual target). */
+    void setNextNPC(uint64_t val) { nextNPC = val; }
+
+    ////////////////////////////////////////////////////////////
+    //
+    // BRANCH PREDICTION
+    //
+    ////////////////////////////////////////////////////////////
+    /** Set the predicted target of this current instruction. */
+    void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; }
+
+    /** Returns the predicted target of the branch. */
+    Addr readPredTarg() { return predPC; }
+
+    /** Returns whether the instruction was predicted taken or not. */
+    bool predTaken() { return predictTaken; }
+
+    /** Returns whether the instruction mispredicted. */
+    bool mispredicted()
+    {
+        // Special case since a not-taken, cond. delay slot, effectively
+        // nullifies the delay slot instruction
+        if (isCondDelaySlot() && !predictTaken) {
+            return predPC != nextPC;
+        } else {
+            return predPC != nextNPC;
+        }
+    }
+
+    /** Returns whether the instruction mispredicted. */
+    bool mistargeted() { return predPC != nextNPC; }
+
+    /** Returns the branch target address. */
+    Addr branchTarget() const { return staticInst->branchTarget(PC); }
+
+    /** Checks whether or not this instruction has had its branch target
+     *  calculated yet.  For now it is not utilized and is hacked to be
+     *  always false.
+     *  @todo: Actually use this instruction.
+     */
+    bool doneTargCalc() { return false; }
+
+    void setBranchPred(bool prediction) { predictTaken = prediction; }
+
+    int squashingStage;
+
+    bool predictTaken;
+
+    bool procDelaySlotOnMispred;
+
+    ////////////////////////////////////////////
+    //
+    // MEMORY ACCESS
+    //
+    ////////////////////////////////////////////
+    /**
+     * Does a read to a given address.
+     * @param addr The address to read.
+     * @param data The read's data is written into this parameter.
+     * @param flags The request's flags.
+     * @return Returns any fault due to the read.
+     */
+    template <class T>
+    Fault read(Addr addr, T &data, unsigned flags);
+
+    /**
+     * Does a write to a given address.
+     * @param data The data to be written.
+     * @param addr The address to write to.
+     * @param flags The request's flags.
+     * @param res The result of the write (for load locked/store conditionals).
+     * @return Returns any fault due to the write.
+     */
+    template <class T>
+    Fault write(T data, Addr addr, unsigned flags,
+                        uint64_t *res);
+
+    /** Initiates a memory access - Calculate Eff. Addr & Initiate Memory Access
+     *  Only valid for memory operations.
+     */
+    Fault initiateAcc();
+
+    /** Completes a memory access - Only valid for memory operations. */
+    Fault completeAcc(Packet *pkt);
+
+    /** Calculates Eff. Addr.  part of a memory instruction.  */
+    Fault calcEA();
+
+    /** Read Effective Address from instruction & do memory access */
+    Fault memAccess();
+
+    RequestPtr memReq;
+
+    bool memAddrReady;
+
+    bool validMemAddr()
+    { return memAddrReady; }
+
+    void setMemAddr(Addr addr)
+    { memAddr = addr; memAddrReady = true;}
+
+    void unsetMemAddr()
+    { memAddrReady = false;}
+
+    Addr getMemAddr()
+    { return memAddr; }
+
+    int getMemAccSize() { return staticInst->memAccSize(this); }
+
+    int getMemFlags() { return staticInst->memAccFlags(); }
+
+    /** Sets the effective address. */
+    void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; }
+
+    /** Returns the effective address. */
+    const Addr &getEA() const { return instEffAddr; }
+
+    /** Returns whether or not the eff. addr. calculation has been completed. */
+    bool doneEACalc() { return eaCalcDone; }
+
+    /** Returns whether or not the eff. addr. source registers are ready.
+     *  Assume that src registers 1..n-1 are the ones that the
+     *  EA calc depends on.  (i.e. src reg 0 is the source of the data to be
+     *  stored)
+     */
+    bool eaSrcsReady()
+    {
+        for (int i = 1; i < numSrcRegs(); ++i) {
+            if (!_readySrcRegIdx[i])
+                return false;
+        }
+
+        return true;
+    }
+
+    //////////////////////////////////////////////////
+    //
+    // SOURCE-DESTINATION REGISTER INDEXING
+    //
+    //////////////////////////////////////////////////
+    /** Returns the number of source registers. */
+    int8_t numSrcRegs()        const { return staticInst->numSrcRegs(); }
+
+    /** Returns the number of destination registers. */
+    int8_t numDestRegs() const { return staticInst->numDestRegs(); }
+
+    // the following are used to track physical register usage
+    // for machines with separate int & FP reg files
+    int8_t numFPDestRegs()  const { return staticInst->numFPDestRegs(); }
+    int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); }
+
+    /** Returns the logical register index of the i'th destination register. */
+    RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); }
+
+    /** Returns the logical register index of the i'th source register. */
+    RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); }
+
+    //////////////////////////////////////////////////
+    //
+    // RENAME/PHYSICAL REGISTER FILE SUPPORT
+    //
+    //////////////////////////////////////////////////
+    /** Returns the physical register index of the i'th destination
+     *  register.
+     */
+    PhysRegIndex renamedDestRegIdx(int idx) const
+    {
+        return _destRegIdx[idx];
+    }
+
+    /** Returns the physical register index of the i'th source register. */
+    PhysRegIndex renamedSrcRegIdx(int idx) const
+    {
+        return _srcRegIdx[idx];
+    }
+
+    /** Returns the physical register index of the previous physical register
+     *  that remapped to the same logical register index.
+     */
+    PhysRegIndex prevDestRegIdx(int idx) const
+    {
+        return _prevDestRegIdx[idx];
+    }
+
+    /** Returns if a source register is ready. */
+    bool isReadySrcRegIdx(int idx) const
+    {
+        return this->_readySrcRegIdx[idx];
+    }
+
+    /** Records that one of the source registers is ready. */
+    void markSrcRegReady()
+    {
+        if (++readyRegs == numSrcRegs()) {
+            status.set(CanIssue);
+        }
+    }
+
+    /** Marks a specific register as ready. */
+    void markSrcRegReady(RegIndex src_idx)
+    {
+        _readySrcRegIdx[src_idx] = true;
+
+        markSrcRegReady();
+    }
+
+    /** Renames a destination register to a physical register.  Also records
+     *  the previous physical register that the logical register mapped to.
+     */
+    void renameDestReg(int idx,
+                       PhysRegIndex renamed_dest,
+                       PhysRegIndex previous_rename)
+    {
+        _destRegIdx[idx] = renamed_dest;
+        _prevDestRegIdx[idx] = previous_rename;
+    }
+
+    /** Renames a source logical register to the physical register which
+     *  has/will produce that logical register's result.
+     *  @todo: add in whether or not the source register is ready.
+     */
+    void renameSrcReg(int idx, PhysRegIndex renamed_src)
+    {
+        _srcRegIdx[idx] = renamed_src;
+    }
+
+
+    PhysRegIndex readDestRegIdx(int idx)
+    {
+        return _destRegIdx[idx];
+    }
+
+    void setDestRegIdx(int idx, PhysRegIndex dest_idx)
+    {
+        _destRegIdx[idx] = dest_idx;
+    }
+
+    int getDestIdxNum(PhysRegIndex dest_idx)
+    {
+        for (int i=0; i < staticInst->numDestRegs(); i++) {
+            if (_destRegIdx[i] == dest_idx)
+                return i;
+        }
+
+        return -1;
+    }
+
+    PhysRegIndex readSrcRegIdx(int idx)
+    {
+        return _srcRegIdx[idx];
+    }
+
+    void setSrcRegIdx(int idx, PhysRegIndex src_idx)
+    {
+        _srcRegIdx[idx] = src_idx;
+    }
+
+    int getSrcIdxNum(PhysRegIndex src_idx)
+    {
+        for (int i=0; i < staticInst->numSrcRegs(); i++) {
+            if (_srcRegIdx[i] == src_idx)
+                return i;
+        }
+
+        return -1;
+    }
+
+    ////////////////////////////////////////////////////
+    //
+    // SOURCE-DESTINATION REGISTER VALUES
+    //
+    ////////////////////////////////////////////////////
+
+    /** Functions that sets an integer or floating point
+     *  source register to a value. */
+    void setIntSrc(int idx, uint64_t val);
+    void setFloatSrc(int idx, FloatReg val, int width = 32);
+    void setFloatRegBitsSrc(int idx, uint64_t val);
+
+    uint64_t* getIntSrcPtr(int idx) { return &instSrc[idx].integer; }
+    uint64_t readIntSrc(int idx) { return instSrc[idx].integer; }
+
+    /** These Instructions read a integer/float/misc. source register
+     *  value in the instruction. The instruction's execute function will
+     *  call these and it is the interface that is used by the ISA descr.
+     *  language (which is why the name isnt readIntSrc(...)) Note: That
+     *  the source reg. value is set using the setSrcReg() function.
+     */
+    IntReg readIntRegOperand(const StaticInst *si, int idx, unsigned tid=0);
+    FloatReg readFloatRegOperand(const StaticInst *si, int idx,
+                          int width = TheISA::SingleWidth);
+    FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
+                                  int width = TheISA::SingleWidth);
+    MiscReg readMiscReg(int misc_reg);
+    MiscReg readMiscRegNoEffect(int misc_reg);
+    MiscReg readMiscRegOperand(const StaticInst *si, int idx);
+    MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx);
+
+    /** Returns the result value instruction. */
+    uint64_t readIntResult(int idx) { return instResult[idx].val.integer; }
+    float readFloatResult(int idx) { return instResult[idx].val.fp; }
+    double readDoubleResult(int idx) { return instResult[idx].val.dbl; }
+    Tick readResultTime(int idx) { return instResult[idx].tick; }
+
+    uint64_t* getIntResultPtr(int idx) { return &instResult[idx].val.integer; }
+
+    /** This is the interface that an instruction will use to write
+     *  it's destination register.
+     */
+    void setIntRegOperand(const StaticInst *si, int idx, IntReg val);
+    void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
+                     int width = TheISA::SingleWidth);
+    void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val,
+                         int width = TheISA::SingleWidth);
+    void setMiscReg(int misc_reg, const MiscReg &val);
+    void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
+    void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val);
+    void setMiscRegOperandNoEffect(const StaticInst *si, int idx, const MiscReg &val);
+
+    virtual uint64_t readRegOtherThread(unsigned idx, int tid = -1);
+    virtual void setRegOtherThread(unsigned idx, const uint64_t &val, int tid = -1);
+
+    //////////////////////////////////////////////////////////////
+    //
+    // INSTRUCTION STATUS FLAGS (READ/SET)
+    //
+    //////////////////////////////////////////////////////////////
+    /** Sets this instruction as entered on the CPU Reg Dep Map */
+    void setRegDepEntry() { status.set(RegDepMapEntry); }
+
+    /** Returns whether or not the entry is on the CPU Reg Dep Map */
+    bool isRegDepEntry() const { return status[RegDepMapEntry]; }
+
+    /** Sets this instruction as completed. */
+    void setCompleted() { status.set(Completed); }
+
+    /** Returns whether or not this instruction is completed. */
+    bool isCompleted() const { return status[Completed]; }
+
+    /** Marks the result as ready. */
+    void setResultReady() { status.set(ResultReady); }
+
+    /** Returns whether or not the result is ready. */
+    bool isResultReady() const { return status[ResultReady]; }
+
+    /** Sets this instruction as ready to issue. */
+    void setCanIssue() { status.set(CanIssue); }
+
+    /** Returns whether or not this instruction is ready to issue. */
+    bool readyToIssue() const { return status[CanIssue]; }
+
+    /** Sets this instruction as issued from the IQ. */
+    void setIssued() { status.set(Issued); }
+
+    /** Returns whether or not this instruction has issued. */
+    bool isIssued() const { return status[Issued]; }
+
+    /** Sets this instruction as executed. */
+    void setExecuted() { status.set(Executed); }
+
+    /** Returns whether or not this instruction has executed. */
+    bool isExecuted() const { return status[Executed]; }
+
+    /** Sets this instruction as ready to commit. */
+    void setCanCommit() { status.set(CanCommit); }
+
+    /** Clears this instruction as being ready to commit. */
+    void clearCanCommit() { status.reset(CanCommit); }
+
+    /** Returns whether or not this instruction is ready to commit. */
+    bool readyToCommit() const { return status[CanCommit]; }
+
+    void setAtCommit() { status.set(AtCommit); }
+
+    bool isAtCommit() { return status[AtCommit]; }
+
+    /** Sets this instruction as committed. */
+    void setCommitted() { status.set(Committed); }
+
+    /** Returns whether or not this instruction is committed. */
+    bool isCommitted() const { return status[Committed]; }
+
+    /** Sets this instruction as squashed. */
+    void setSquashed() { status.set(Squashed); }
+
+    /** Returns whether or not this instruction is squashed. */
+    bool isSquashed() const { return status[Squashed]; }
+
+    /** Temporarily sets this instruction as a serialize before instruction. */
+    void setSerializeBefore() { status.set(SerializeBefore); }
+
+    /** Clears the serializeBefore part of this instruction. */
+    void clearSerializeBefore() { status.reset(SerializeBefore); }
+
+    /** Checks if this serializeBefore is only temporarily set. */
+    bool isTempSerializeBefore() { return status[SerializeBefore]; }
+
+    /** Temporarily sets this instruction as a serialize after instruction. */
+    void setSerializeAfter() { status.set(SerializeAfter); }
+
+    /** Clears the serializeAfter part of this instruction.*/
+    void clearSerializeAfter() { status.reset(SerializeAfter); }
+
+    /** Checks if this serializeAfter is only temporarily set. */
+    bool isTempSerializeAfter() { return status[SerializeAfter]; }
+
+    /** Sets the serialization part of this instruction as handled. */
+    void setSerializeHandled() { status.set(SerializeHandled); }
+
+    /** Checks if the serialization part of this instruction has been
+     *  handled.  This does not apply to the temporary serializing
+     *  state; it only applies to this instruction's own permanent
+     *  serializing state.
+     */
+    bool isSerializeHandled() { return status[SerializeHandled]; }
+
+  private:
+    /** Instruction effective address.
+     *  @todo: Consider if this is necessary or not.
+     */
+    Addr instEffAddr;
+
+    /** Whether or not the effective address calculation is completed.
+     *  @todo: Consider if this is necessary or not.
+     */
+    bool eaCalcDone;
+
+  public:
+    /** Whether or not the memory operation is done. */
+    bool memOpDone;
+
+  public:
+    /** Load queue index. */
+    int16_t lqIdx;
+
+    /** Store queue index. */
+    int16_t sqIdx;
+
+    /** Iterator pointing to this BaseDynInst in the list of all insts. */
+    ListIt instListIt;
+
+    /** Returns iterator to this instruction in the list of all insts. */
+    ListIt &getInstListIt() { return instListIt; }
+
+    /** Sets iterator for this instruction in the list of all insts. */
+    void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; }
+
+    /** Count of total number of dynamic instructions. */
+    static int instcount;
+
+#ifdef DEBUG
+    void dumpSNList();
+#endif
+
+    /** Dumps out contents of this BaseDynInst. */
+    void dump();
+
+    /** Dumps out contents of this BaseDynInst into given string. */
+    void dump(std::string &outstring);
+
+
+  //inline int curCount() { return curCount(); }
+};
+
+
+#endif // __CPU_BASE_DYN_INST_HH__
diff --git a/src/cpu/inorder/inorder_trace.cc b/src/cpu/inorder/inorder_trace.cc
new file mode 100644 (file)
index 0000000..f12a1b7
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * Copyright (c) 2001-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: Korey Sewell
+ */
+
+#include <iomanip>
+
+#include "cpu/exetrace.hh"
+#include "cpu/inorder/inorder_trace.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/thread_context.hh"
+#include "params/InOrderTrace.hh"
+
+using namespace std;
+using namespace TheISA;
+
+namespace Trace {
+
+inline void
+Trace::InOrderTraceRecord::dumpTicks(std::ostream &outs)
+{
+  if (!stageTrace) {
+    ccprintf(outs, "%7d: ", when);
+  } else {
+    ccprintf(outs, "");
+    for (int i=0; i < stageCycle.size(); i++) {
+        if (i < stageCycle.size() - 1)
+            outs << dec << stageCycle[i] << "-";
+        else
+            outs << dec << stageCycle[i] << ":";
+    }
+  }
+}
+
+InOrderTraceRecord *
+InOrderTrace::getInstRecord(unsigned num_stages, bool stage_tracing,
+        ThreadContext *tc)
+{
+    if (!IsOn(ExecEnable))
+        return NULL;
+
+    if (!Trace::enabled)
+        return NULL;
+
+    return new InOrderTraceRecord(num_stages, stage_tracing, tc);
+}
+
+InOrderTraceRecord *
+InOrderTrace::getInstRecord(Tick when, ThreadContext *tc,
+        const StaticInstPtr staticInst, Addr pc,
+        const StaticInstPtr macroStaticInst, MicroPC upc)
+{
+    return new InOrderTraceRecord(ThePipeline::NumStages, true, tc);
+}
+
+/* namespace Trace */ }
+
+////////////////////////////////////////////////////////////////////////
+//
+//  ExeTracer Simulation Object
+//
+Trace::InOrderTrace *
+InOrderTraceParams::create()
+{
+    return new Trace::InOrderTrace(this);
+};
+
diff --git a/src/cpu/inorder/inorder_trace.hh b/src/cpu/inorder/inorder_trace.hh
new file mode 100644 (file)
index 0000000..4338b43
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * Copyright (c) 2001-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: Korey Sewell
+ */
+
+#ifndef __INORDERTRACE_HH__
+#define __INORDERTRACE_HH__
+
+#include "base/trace.hh"
+#include "cpu/static_inst.hh"
+#include "sim/host.hh"
+#include "sim/insttracer.hh"
+#include "params/InOrderTrace.hh"
+#include "cpu/exetrace.hh"
+
+class ThreadContext;
+
+
+namespace Trace {
+
+class InOrderTraceRecord : public ExeTracerRecord
+{
+  public:
+    InOrderTraceRecord(unsigned num_stages, bool _stage_tracing,
+           ThreadContext *_thread, bool spec = false)
+        : ExeTracerRecord(0, _thread, NULL, 0, spec)
+    {
+        stageTrace = _stage_tracing;
+        stageCycle.resize(num_stages);
+    }
+
+    // Trace stage-by-stage execution of instructions.
+    bool stageTrace;
+    std::vector<Tick> stageCycle;
+
+    void dumpTicks(std::ostream &outs);
+
+    void
+    setStageCycle(int num_stage, Tick cur_cycle)
+    {
+        if (stageTrace) {
+            stageCycle[num_stage] = cur_cycle;
+        } else {
+            when = cur_cycle;
+        }
+    }
+
+    void
+    setStaticInst(const StaticInstPtr &_staticInst)
+    {
+        staticInst = _staticInst;
+    }
+    void setPC(Addr _pc) { PC = _pc; }
+};
+
+class InOrderTrace : public InstTracer
+{
+  public:
+    InOrderTrace(const InOrderTraceParams *p) : InstTracer(p)
+    {}
+
+    InOrderTraceRecord *
+    getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc);
+
+    virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
+            const StaticInstPtr staticInst, Addr pc,
+            const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0);
+};
+
+/* namespace Trace */ }
+
+#endif // __EXETRACE_HH__
diff --git a/src/cpu/inorder/params.hh b/src/cpu/inorder/params.hh
new file mode 100644 (file)
index 0000000..67f8f47
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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: Korey Sewell
+ */
+
+#ifndef __CPU_INORDER_PARAMS_HH__
+#define __CPU_INORDER_PARAMS_HH__
+
+#include "cpu/base.hh"
+
+//Forward declarations
+class FunctionalMemory;
+class Process;
+class MemObject;
+class MemInterface;
+
+/**
+ * This file defines the parameters that will be used for the InOrderCPU.
+ * This must be defined externally so that the Impl can have a params class
+ * defined that it can pass to all of the individual stages.
+ */
+
+class InOrderParams : public BaseCPU::Params
+{
+  public:
+
+    // Workloads
+#if !FULL_SYSTEM
+    std::vector<Process *> workload;
+    Process *process;
+#endif // FULL_SYSTEM
+
+    //
+    // Memory System/Caches
+    //
+    unsigned cachePorts;
+    std::string fetchMemPort;
+    std::string dataMemPort;
+
+    //
+    // Branch predictor (BP & BTB)
+    //
+    std::string predType;
+    unsigned localPredictorSize;
+    unsigned localCtrBits;
+    unsigned localHistoryTableSize;
+    unsigned localHistoryBits;
+    unsigned globalPredictorSize;
+    unsigned globalCtrBits;
+    unsigned globalHistoryBits;
+    unsigned choicePredictorSize;
+    unsigned choiceCtrBits;
+    unsigned BTBEntries;
+    unsigned BTBTagSize;
+    unsigned RASSize;
+
+    // Pipeline Parameters
+    unsigned stageWidth;
+
+    // InOrderCPU Simulation Parameters
+    unsigned instShiftAmt;
+    unsigned activity;
+    unsigned deferRegistration;
+
+    //
+    // Memory Parameters
+    //
+    unsigned memBlockSize;
+
+    //
+    // Multiply Divide Unit
+    //
+    // @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr,
+    // then MDU must be defined as its own SimObject so that an arbitrary # can
+    // be defined with different parameters
+    /** 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;
+
+
+};
+
+#endif // __CPU_O3_CPU_INORDER_PARAMS_HH__
diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc
new file mode 100644 (file)
index 0000000..547b425
--- /dev/null
@@ -0,0 +1,1033 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include "base/str.hh"
+#include "cpu/inorder/pipeline_stage.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+PipelineStage::PipelineStage(Params *params, unsigned stage_num)
+    : numThreads(ThePipeline::MaxThreads)
+{
+    stageNum = stage_num;
+    stageWidth = ThePipeline::StageWidth;
+
+    _status = Inactive;
+
+    prevStageValid = false;
+    nextStageValid = false;
+
+    // Init. structures
+    for(int tid=0; tid < numThreads; tid++) {
+        stageStatus[tid] = Idle;
+
+        for (int stNum = 0; stNum < NumStages; stNum++) {
+            stalls[tid].stage[stNum] = false;
+        }
+        stalls[tid].resources.clear();
+
+        if (stageNum < BackEndStartStage)
+            lastStallingStage[tid] = BackEndStartStage - 1;
+        else
+            lastStallingStage[tid] = NumStages - 1;
+    }
+
+    stageBufferMax = ThePipeline::interStageBuffSize[stage_num];
+}
+
+
+void
+PipelineStage::init(Params *params, unsigned stage_num)
+{
+    stageNum = stage_num;
+    stageWidth = ThePipeline::StageWidth;
+
+    _status = Inactive;
+
+    numThreads = ThePipeline::MaxThreads;
+
+    prevStageValid = false;
+    nextStageValid = false;
+
+    // Init. structures
+    for(int tid=0; tid < numThreads; tid++) {
+        stageStatus[tid] = Idle;
+
+        for (int stNum = 0; stNum < NumStages; stNum++) {
+            stalls[tid].stage[stNum] = false;
+        }
+        stalls[tid].resources.clear();
+
+        if (stageNum < BackEndStartStage)
+            lastStallingStage[tid] = BackEndStartStage - 1;
+        else
+            lastStallingStage[tid] = NumStages - 1;
+    }
+
+    stageBufferMax = ThePipeline::interStageBuffSize[stage_num];
+}
+
+
+std::string
+PipelineStage::name() const
+{
+    return cpu->name() + ".stage-" + to_string(stageNum);
+}
+
+
+void
+PipelineStage::regStats()
+{
+/*    stageIdleCycles
+        .name(name() + ".IdleCycles")
+        .desc("Number of cycles stage is idle")
+        .prereq(stageIdleCycles);
+    stageBlockedCycles
+        .name(name() + ".BlockedCycles")
+        .desc("Number of cycles stage is blocked")
+        .prereq(stageBlockedCycles);
+    stageRunCycles
+        .name(name() + ".RunCycles")
+        .desc("Number of cycles stage is running")
+        .prereq(stageRunCycles);
+    stageUnblockCycles
+        .name(name() + ".UnblockCycles")
+        .desc("Number of cycles stage is unblocking")
+        .prereq(stageUnblockCycles);
+    stageSquashCycles
+        .name(name() + ".SquashCycles")
+        .desc("Number of cycles stage is squashing")
+        .prereq(stageSquashCycles);
+    stageProcessedInsts
+        .name(name() + ".ProcessedInsts")
+        .desc("Number of instructions handled by stage")
+        .prereq(stageProcessedInsts);
+    stageSquashedInsts
+        .name(name() + ".SquashedInsts")
+        .desc("Number of squashed instructions handled by stage")
+        .prereq(stageSquashedInsts);*/
+}
+
+
+void
+PipelineStage::setCPU(InOrderCPU *cpu_ptr)
+{
+    cpu = cpu_ptr;
+
+    dummyBufferInst = new InOrderDynInst(cpu_ptr, NULL, 0, 0);
+
+    DPRINTF(InOrderStage, "Set CPU pointer.\n");
+
+    tracer = dynamic_cast<Trace::InOrderTrace *>(cpu->getTracer());
+}
+
+
+void
+PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+    DPRINTF(InOrderStage, "Setting time buffer pointer.\n");
+    timeBuffer = tb_ptr;
+
+    // Setup wire to write information back to fetch.
+    toPrevStages = timeBuffer->getWire(0);
+
+    // Create wires to get information from proper places in time buffer.
+    fromNextStages = timeBuffer->getWire(-1);
+}
+
+
+void
+PipelineStage::setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr)
+{
+    DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n");
+    prevStageQueue = prev_stage_ptr;
+
+    // Setup wire to read information from fetch queue.
+    prevStage = prevStageQueue->getWire(-1);
+
+    prevStageValid = true;
+}
+
+
+
+void
+PipelineStage::setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr)
+{
+    DPRINTF(InOrderStage, "Setting next stage pointer.\n");
+    nextStageQueue = next_stage_ptr;
+
+    // Setup wire to write information to proper place in stage queue.
+    nextStage = nextStageQueue->getWire(0);
+
+    nextStageValid = true;
+}
+
+
+
+void
+PipelineStage::setActiveThreads(list<unsigned> *at_ptr)
+{
+    DPRINTF(InOrderStage, "Setting active threads list pointer.\n");
+    activeThreads = at_ptr;
+}
+
+/*inline void
+PipelineStage::switchToActive()
+{
+   if (_status == Inactive) {
+        DPRINTF(Activity, "Activating stage.\n");
+
+        cpu->activateStage(stageNum);
+
+        _status = Active;
+    }
+}*/
+
+void
+PipelineStage::switchOut()
+{
+    // Stage can immediately switch out.
+    cpu->signalSwitched();
+}
+
+
+void
+PipelineStage::takeOverFrom()
+{
+    _status = Inactive;
+
+    // Be sure to reset state and clear out any old instructions.
+    for (int i = 0; i < numThreads; ++i) {
+        stageStatus[i] = Idle;
+
+        for (int stNum = 0; stNum < NumStages; stNum++) {
+            stalls[i].stage[stNum] = false;
+        }
+
+        stalls[i].resources.clear();
+
+        while (!insts[i].empty())
+            insts[i].pop();
+
+        while (!skidBuffer[i].empty())
+            skidBuffer[i].pop();
+    }
+    wroteToTimeBuffer = false;
+}
+
+
+
+bool
+PipelineStage::checkStall(unsigned tid) const
+{
+    bool ret_val = false;
+
+    // Only check pipeline stall from stage directly following this stage
+    if (stalls[tid].stage[stageNum + 1]) {
+        DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n",
+                tid, stageNum + 1);
+        ret_val = true;
+    }
+
+    if (!stalls[tid].resources.empty()) {
+        string stall_src;
+
+        for (int i=0; i < stalls[tid].resources.size(); i++) {
+            stall_src += stalls[tid].resources[i]->res->name() + ":";
+        }
+
+        DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n",
+                tid, stall_src);
+        ret_val = true;
+    }
+
+    return ret_val;
+}
+
+
+void
+PipelineStage::removeStalls(unsigned tid)
+{
+    for (int stNum = 0; stNum < NumStages; stNum++) {
+        stalls[tid].stage[stNum] = false;
+    }
+    stalls[tid].resources.clear();
+}
+
+inline bool
+PipelineStage::prevStageInstsValid()
+{
+    return prevStage->size > 0;
+}
+
+bool
+PipelineStage::isBlocked(unsigned tid)
+{
+    return stageStatus[tid] == Blocked;
+}
+
+bool
+PipelineStage::block(unsigned tid)
+{
+    DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to previous stages.\n", tid);
+
+    // Add the current inputs to the skid buffer so they can be
+    // reprocessed when this stage unblocks.
+    // skidInsert(tid);
+
+    // If the stage status is blocked or unblocking then stage has not yet
+    // signalled fetch to unblock. In that case, there is no need to tell
+    // fetch to block.
+    if (stageStatus[tid] != Blocked) {
+        // Set the status to Blocked.
+        stageStatus[tid] = Blocked;
+
+        if (stageStatus[tid] != Unblocking) {
+            if (prevStageValid)
+                toPrevStages->stageBlock[stageNum][tid] = true;
+            wroteToTimeBuffer = true;
+        }
+
+        return true;
+    }
+
+
+    return false;
+}
+
+void
+PipelineStage::blockDueToBuffer(unsigned tid)
+{
+    DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to next stage.\n", tid);
+
+    if (stageStatus[tid] != Blocked) {
+        // Set the status to Blocked.
+        stageStatus[tid] = Blocked;
+
+        if (stageStatus[tid] != Unblocking) {
+            wroteToTimeBuffer = true;
+        }
+    }
+}
+
+bool
+PipelineStage::unblock(unsigned tid)
+{
+    // Stage is done unblocking only if the skid buffer is empty.
+    if (skidBuffer[tid].empty()) {
+        DPRINTF(InOrderStage, "[tid:%u]: Done unblocking.\n", tid);
+
+        if (prevStageValid)
+            toPrevStages->stageUnblock[stageNum][tid] = true;
+
+        wroteToTimeBuffer = true;
+
+        stageStatus[tid] = Running;
+
+        return true;
+    }
+
+    DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid);
+    return false;
+}
+
+void
+PipelineStage::squashDueToBranch(DynInstPtr &inst, unsigned tid)
+{
+    if (cpu->squashSeqNum[tid] < inst->seqNum &&
+        cpu->lastSquashCycle[tid] == curTick){
+        DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another stage's squash "
+                "signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]);
+    } else {
+        // Send back mispredict information.
+        toPrevStages->stageInfo[stageNum][tid].branchMispredict = true;
+        toPrevStages->stageInfo[stageNum][tid].predIncorrect = true;
+        toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum;
+        toPrevStages->stageInfo[stageNum][tid].squash = true;
+        toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg();
+        toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextNPC() !=
+            (inst->readNextPC() + sizeof(TheISA::MachInst));
+        toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->bdelaySeqNum;
+
+        DPRINTF(InOrderStage, "Target being re-set to %08p\n", inst->readPredTarg());
+        InstSeqNum squash_seq_num = inst->bdelaySeqNum;
+
+        DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], due to [sn:%i] "
+                "branch.\n", tid, squash_seq_num, inst->seqNum);
+
+        // Save squash num for later stage use
+        cpu->squashSeqNum[tid] = squash_seq_num;
+        cpu->lastSquashCycle[tid] = curTick;
+    }
+}
+
+void
+PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num,
+                                    unsigned tid)
+{
+    DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from "
+            "incoming stage queue.\n", tid);
+
+    for (int i=0; i < prevStage->size; i++) {
+        if (prevStage->insts[i]->threadNumber == tid &&
+            prevStage->insts[i]->seqNum > squash_seq_num) {
+            DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, "
+                    "[sn:%i] PC %08p.\n",
+                    tid,
+                    prevStage->insts[i]->seqNum,
+                    prevStage->insts[i]->readPC());
+            prevStage->insts[i]->setSquashed();
+        }
+    }
+}
+
+void
+PipelineStage::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+    // Set status to squashing.
+    stageStatus[tid] = Squashing;
+
+    squashPrevStageInsts(squash_seq_num, tid);
+
+    DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage skidbuffer.\n",
+            tid);
+    while (!skidBuffer[tid].empty()) {
+        if (skidBuffer[tid].front()->seqNum <= squash_seq_num) {
+            DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer "
+                    "instructions before delay slot [sn:%i]. %i insts"
+                    "left.\n", tid, squash_seq_num,
+                    skidBuffer[tid].size());
+            break;
+        }
+        DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
+                tid, skidBuffer[tid].front()->seqNum, skidBuffer[tid].front()->PC);
+        skidBuffer[tid].pop();
+    }
+
+}
+
+int
+PipelineStage::stageBufferAvail()
+{
+    unsigned total = 0;
+
+    for (int i=0; i < ThePipeline::MaxThreads; i++) {
+        total += skidBuffer[i].size();
+    }
+
+    int incoming_insts = (prevStageValid) ?
+        cpu->pipelineStage[stageNum-1]->nextStage->size :
+        0;
+
+    int avail = stageBufferMax - total - incoming_insts;
+
+    assert(avail >= 0);
+
+    return avail;
+}
+
+bool
+PipelineStage::canSendInstToNextStage()
+{
+    bool buffer_avail = false;
+
+    if (nextStageValid) {
+        buffer_avail = (cpu->pipelineStage[stageNum+1]->stageBufferAvail() >= 1);
+    }
+
+    if (!buffer_avail && nextStageValid) {
+        DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1);
+    }
+
+    return buffer_avail;
+}
+
+void
+PipelineStage::skidInsert(unsigned tid)
+{
+    DynInstPtr inst = NULL;
+
+    while (!insts[tid].empty()) {
+        inst = insts[tid].front();
+
+        insts[tid].pop();
+
+        assert(tid == inst->threadNumber);
+
+        DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n",
+                tid, inst->seqNum, inst->readPC(), inst->threadNumber);
+
+        skidBuffer[tid].push(inst);
+    }
+}
+
+
+
+bool
+PipelineStage::skidsEmpty()
+{
+    list<unsigned>::iterator threads = (*activeThreads).begin();
+
+    while (threads != (*activeThreads).end()) {
+        if (!skidBuffer[*threads++].empty())
+            return false;
+    }
+
+    return true;
+}
+
+
+
+void
+PipelineStage::updateStatus()
+{
+    bool any_unblocking = false;
+
+    list<unsigned>::iterator threads = (*activeThreads).begin();
+
+    threads = (*activeThreads).begin();
+
+    while (threads != (*activeThreads).end()) {
+        unsigned tid = *threads++;
+
+        if (stageStatus[tid] == Unblocking) {
+            any_unblocking = true;
+            break;
+        }
+    }
+
+    // Stage will have activity if it's unblocking.
+    if (any_unblocking) {
+        if (_status == Inactive) {
+            _status = Active;
+
+            DPRINTF(Activity, "Activating stage.\n");
+
+            cpu->activateStage(stageNum);
+        }
+    } else {
+        // If it's not unblocking, then stage will not have any internal
+        // activity.  Switch it to inactive.
+        if (_status == Active) {
+            _status = Inactive;
+            DPRINTF(Activity, "Deactivating stage.\n");
+
+            cpu->deactivateStage(stageNum);
+        }
+    }
+}
+
+
+
+void
+PipelineStage::sortInsts()
+{
+    if (prevStageValid) {
+        int insts_from_prev_stage = prevStage->size;
+
+        DPRINTF(InOrderStage, "%i insts available from previous stage.\n",
+                insts_from_prev_stage);
+
+        for (int i = 0; i < insts_from_prev_stage; ++i) {
+
+            if (prevStage->insts[i]->isSquashed()) {
+                DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], not inserting "
+                        "into stage buffer.\n",
+                    prevStage->insts[i]->readTid(),
+                    prevStage->insts[i]->seqNum);
+
+                continue;
+            }
+
+            DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage buffer.\n",
+                    prevStage->insts[i]->readTid(),
+                    prevStage->insts[i]->seqNum);
+
+            int tid = prevStage->insts[i]->threadNumber;
+
+            DynInstPtr inst = prevStage->insts[i];
+
+            skidBuffer[tid].push(prevStage->insts[i]);
+
+            prevStage->insts[i] = dummyBufferInst;
+
+        }
+    }
+}
+
+
+
+void
+PipelineStage::readStallSignals(unsigned tid)
+{
+    for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid];
+         stage_idx++) {
+
+        // Check for Stage Blocking Signal
+        if (fromNextStages->stageBlock[stage_idx][tid]) {
+            stalls[tid].stage[stage_idx] = true;
+        }
+
+        // Check for Stage Unblocking Signal
+        if (fromNextStages->stageUnblock[stage_idx][tid]) {
+            //assert(fromNextStages->stageBlock[stage_idx][tid]);
+            stalls[tid].stage[stage_idx] = false;
+        }
+    }
+}
+
+
+
+bool
+PipelineStage::checkSignalsAndUpdate(unsigned tid)
+{
+    // Check if there's a squash signal, squash if there is.
+    // Check stall signals, block if necessary.
+    // If status was blocked
+    //     Check if stall conditions have passed
+    //         if so then go to unblocking
+    // If status was Squashing
+    //     check if squashing is not high.  Switch to running this cycle.
+
+    // Update the per thread stall statuses.
+    readStallSignals(tid);
+
+    // Check for squash from later pipeline stages
+    for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) {
+        if (fromNextStages->stageInfo[stage_idx][tid].squash) {
+            DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to squash "
+                "from stage %u.\n", tid, stage_idx);
+            InstSeqNum squash_seq_num = fromNextStages->
+                stageInfo[stage_idx][tid].bdelayDoneSeqNum;
+            squash(squash_seq_num, tid);
+            break; //return true;
+        }
+    }
+
+    if (checkStall(tid)) {
+        return block(tid);
+    }
+
+    if (stageStatus[tid] == Blocked) {
+        DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to unblocking.\n",
+                tid);
+
+        stageStatus[tid] = Unblocking;
+
+        unblock(tid);
+
+        return true;
+    }
+
+    if (stageStatus[tid] == Squashing) {
+        if (!skidBuffer[tid].empty()) {
+            DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to unblocking.\n",
+                    tid);
+
+            stageStatus[tid] = Unblocking;
+        } else {
+            // Switch status to running if stage isn't being told to block or
+            // squash this cycle.
+            DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to running.\n",
+                    tid);
+
+            stageStatus[tid] = Running;
+        }
+
+        return true;
+    }
+
+    // If we've reached this point, we have not gotten any signals that
+    // cause stage to change its status.  Stage remains the same as before.*/
+    return false;
+}
+
+
+
+void
+PipelineStage::tick()
+{
+    wroteToTimeBuffer = false;
+
+    bool status_change = false;
+
+    toNextStageIndex = 0;
+
+    sortInsts();
+
+    processStage(status_change);
+
+    if (status_change) {
+        updateStatus();
+    }
+
+    if (wroteToTimeBuffer) {
+        DPRINTF(Activity, "Activity this cycle.\n");
+        cpu->activityThisCycle();
+    }
+
+    DPRINTF(InOrderStage, "\n\n");
+}
+
+bool
+PipelineStage::outOfOrderValid()
+{
+    //@TODO: Define this function when OOO is valid
+    return false;
+}
+
+void
+PipelineStage::setResStall(ResReqPtr res_req, unsigned tid)
+{
+    DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name());
+    stalls[tid].resources.push_back(res_req);
+}
+
+void
+PipelineStage::unsetResStall(ResReqPtr res_req, unsigned tid)
+{
+    // Search through stalls to find stalling request and then
+    // remove it
+    vector<ResReqPtr>::iterator req_it = stalls[tid].resources.begin();
+    vector<ResReqPtr>::iterator req_end = stalls[tid].resources.end();
+
+    while (req_it != req_end) {
+        if( (*req_it)->res ==  res_req->res && // Same Resource
+            (*req_it)->inst ==  res_req->inst && // Same Instruction
+            (*req_it)->getSlot() ==  res_req->getSlot()) {
+            DPRINTF(InOrderStage, "[tid:%u]: Clearing stall by %s.\n",
+                    tid, res_req->res->name());
+            stalls[tid].resources.erase(req_it);
+            break;
+        }
+
+        req_it++;
+    }
+
+    if (stalls[tid].resources.size() == 0) {
+        DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource stalls.\n",
+                tid);
+    }
+}
+
+// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be handled
+// one at a time, but instead first come first serve by instruction?
+// Questions are how should a pipeline stage handle thread-specific stalls &
+// pipeline squashes
+void
+PipelineStage::processStage(bool &status_change)
+{
+    list<unsigned>::iterator threads = (*activeThreads).begin();
+
+    //Check stall and squash signals.
+    while (threads != (*activeThreads).end()) {
+        unsigned tid = *threads++;
+
+        DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid);
+        status_change =  checkSignalsAndUpdate(tid) || status_change;
+
+        processThread(status_change, tid);
+    }
+
+    if (nextStageValid) {
+        DPRINTF(InOrderStage, "%i insts now available for stage %i.\n",
+                nextStage->size, stageNum + 1);
+    }
+
+    DPRINTF(InOrderStage, "%i insts left in stage buffer.\n", stageBufferMax - stageBufferAvail());
+
+}
+
+void
+PipelineStage::processThread(bool &status_change, unsigned tid)
+{
+    // If status is Running or idle,
+    //     call stageInsts()
+    // If status is Unblocking,
+    //     buffer any instructions coming from fetch
+    //     continue trying to empty skid buffer
+    //     check if stall conditions have passed
+
+    if (stageStatus[tid] == Blocked) {
+        ;//++stageBlockedCycles;
+    } else if (stageStatus[tid] == Squashing) {
+        ;//++stageSquashCycles;
+    }
+
+    // Stage should try to stage as many instructions as its bandwidth
+    // will allow, as long as it is not currently blocked.
+    if (stageStatus[tid] == Running ||
+        stageStatus[tid] == Idle) {
+        DPRINTF(InOrderStage, "[tid:%u]: Not blocked, so attempting to run "
+                "stage.\n",tid);
+
+        processInsts(tid);
+    } else if (stageStatus[tid] == Unblocking) {
+        // Make sure that the skid buffer has something in it if the
+        // status is unblocking.
+        assert(!skidsEmpty());
+
+        // If the status was unblocking, then instructions from the skid
+        // buffer were used.  Remove those instructions and handle
+        // the rest of unblocking.
+        processInsts(tid);
+
+        if (prevStageValid && prevStageInstsValid()) {
+            // Add the current inputs to the skid buffer so they can be
+            // reprocessed when this stage unblocks.
+            skidInsert(tid);
+        }
+
+        status_change = unblock(tid) || status_change;
+    }
+}
+
+
+void
+PipelineStage::processInsts(unsigned tid)
+{
+    // Instructions can come either from the skid buffer or the list of
+    // instructions coming from fetch, depending on stage's status.
+    int insts_available = skidBuffer[tid].size();
+
+    std::queue<DynInstPtr> &insts_to_stage = skidBuffer[tid];
+
+    if (insts_available == 0) {
+        DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out"
+                " early.\n",tid);
+        // Should I change the status to idle?
+        //++stageIdleCycles;
+        return;
+    }
+
+    DynInstPtr inst;
+    bool last_req_completed = true;
+
+    int insts_processed = 0;
+
+    DPRINTF(InOrderStage, "[tid:%u]: Sending instructions to stage %u.\n", tid,
+            stageNum+1);
+
+    //Keep processing instructions while ... these ?s are true:
+    while (insts_available > 0 &&                            //1. are there instructions to process
+           insts_processed < stageWidth &&                   //2. can the stage still process this
+           (canSendInstToNextStage() || !nextStageValid) &&  //3. is there room in next stage
+           last_req_completed) {                             //4. was the last instruction completed
+        assert(!insts_to_stage.empty());
+
+        inst = insts_to_stage.front();
+
+        DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] with "
+                "PC %#x\n",
+                tid, inst->seqNum, inst->readPC());
+
+        if (inst->isSquashed()) {
+            DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %#x is "
+                    "squashed, skipping.\n",
+                    tid, inst->seqNum, inst->readPC());
+
+            //++stageSquashedInsts;
+
+            insts_to_stage.pop();
+
+            --insts_available;
+
+            continue;
+        }
+
+
+        last_req_completed = processInstSchedule(inst);
+
+
+        insts_processed++;
+
+        // Don't let instruction pass to next stage if it hasnt completed
+        // all of it's requests for this stage.
+        if (!last_req_completed && !outOfOrderValid())
+            continue;
+
+        insts_to_stage.pop();
+
+        DPRINTF(InOrderStage, "Marking [tid:%i] [sn:%i] for insertion into next stage buffer.\n",
+                tid, inst->seqNum);
+
+        // Send to Next Stage or Break Loop
+        if (!sendInstToNextStage(inst))
+            break;;
+
+
+        //++stageProcessedInsts;
+        --insts_available;
+    }
+
+    // If we didn't process all instructions, then we will need to block
+    // and put all those instructions into the skid buffer.
+    // @TODO:-IN-PROGRESS-:Evaluating when stages should block/unblock
+    // for stage stalls...
+    if (!insts_to_stage.empty()) {
+        blockDueToBuffer(tid);
+    }
+
+    // Record that stage has written to the time buffer for activity
+    // tracking.
+    if (toNextStageIndex) {
+        wroteToTimeBuffer = true;
+    }
+}
+
+bool
+PipelineStage::processInstSchedule(DynInstPtr inst)
+{
+    bool last_req_completed = true;
+    int tid;
+
+    tid = inst->readTid();
+
+    if (inst->nextResStage() == stageNum) {
+        int res_stage_num = inst->nextResStage();
+
+        while (res_stage_num == stageNum) {
+            int res_num = inst->nextResource();
+
+
+            DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s.\n",
+                    tid, inst->seqNum, cpu->resPool->name(res_num));
+
+            ResReqPtr req = cpu->resPool->request(res_num, inst);
+
+            if (req->isCompleted()) {
+                DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s completed.\n",
+                        tid, inst->seqNum, cpu->resPool->name(res_num));
+
+                if (req->fault == NoFault) {
+                    inst->popSchedEntry();
+                } else {
+                    panic("%i: encountered %s fault!\n",
+                          curTick, req->fault->name());
+                }
+            } else {
+                DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed.\n",
+                        tid, inst->seqNum, cpu->resPool->name(res_num));
+
+                last_req_completed = false;
+
+                break;
+            }
+
+            res_stage_num = inst->nextResStage();
+        }
+    } else {
+        DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %#x "
+                " needed no resources in stage %i.\n",
+                tid, inst->seqNum, inst->readPC(), stageNum);
+    }
+
+    return last_req_completed;
+}
+
+bool
+PipelineStage::nextStageQueueValid(int stage_num)
+{
+    return cpu->pipelineStage[stage_num]->nextStageValid;
+}
+
+
+bool
+PipelineStage::sendInstToNextStage(DynInstPtr inst)
+{
+    // Update Next Stage Variable in Instruction
+    if (inst->nextStage == stageNum)
+        inst->nextStage++;
+
+    bool success = false;
+    int tid = inst->readTid();
+    int next_stage = inst->nextStage;
+    int prev_stage = next_stage - 1;
+
+    if (nextStageQueueValid(inst->nextStage - 1)) {
+        if (inst->seqNum > cpu->squashSeqNum[tid] &&
+            curTick == cpu->lastSquashCycle[tid]) {
+            DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion "
+                    "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage);
+        } else {
+            DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n",
+                    tid, cpu->pipelineStage[next_stage]->stageBufferAvail());
+
+            DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into  "
+                    "index %i stage %i queue.\n",
+                    tid, inst->seqNum, toNextStageIndex, inst->nextStage);
+
+            int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size;
+
+            // Place instructions in inter-stage communication struct for the next
+            // pipeline stage to read next cycle
+            cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] = inst;
+
+            ++(cpu->pipelineStage[prev_stage]->nextStage->size);
+
+            ++toNextStageIndex;
+
+            success = true;
+
+            // Take note of trace data for this inst & stage
+            if (inst->traceData) {
+                inst->traceData->setStageCycle(stageNum, curTick);
+            }
+
+        }
+    }
+
+    return success;
+}
+
+void
+PipelineStage::dumpInsts()
+{
+    std::cerr << "Insts in Stage " << stageNum << " skidbuffers:" << endl;
+
+    for (int tid=0; tid < ThePipeline::MaxThreads; tid++) {
+
+        std::queue<DynInstPtr> copy_buff(skidBuffer[tid]);
+
+        while (!copy_buff.empty()) {
+            DynInstPtr inst = copy_buff.front();
+
+            cprintf("Inst. PC:%#x\n[tid:%i]\n[sn:%i]\n\n",
+                    inst->readPC(), inst->threadNumber, inst->seqNum);
+
+            copy_buff.pop();
+        }
+    }
+
+}
diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh
new file mode 100644 (file)
index 0000000..8335477
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * 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_PIPELINE_STAGE_HH__
+#define __CPU_INORDER_PIPELINE_STAGE_HH__
+
+#include <queue>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/comm.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+class InOrderCPU;
+
+class PipelineStage
+{
+  protected:
+    typedef ThePipeline::Params Params;
+    typedef ThePipeline::DynInstPtr DynInstPtr;
+
+  public:
+    /** Overall stage status. Used to determine if the CPU can
+     * deschedule itself due to a lack of activity.
+     */
+    enum StageStatus {
+        Active,
+        Inactive
+    };
+
+    /** Individual thread status. */
+    enum ThreadStatus {
+        Running,
+        Idle,
+        StartSquash,
+        Squashing,
+        Blocked,
+        Unblocking,
+        MemWaitResponse,
+        MemWaitRetry,
+        MemAccessComplete
+    };
+
+  protected:
+    /** The Number of This Pipeline Stage */
+    unsigned stageNum;
+
+    /** The width of stage, in instructions. */
+    unsigned stageWidth;
+
+    /** Number of Threads*/
+    unsigned numThreads;
+
+    /** Stage status. */
+    StageStatus _status;
+
+    /** Per-thread status. */
+    ThreadStatus stageStatus[ThePipeline::MaxThreads];
+
+  public:
+    PipelineStage(Params *params, unsigned stage_num);
+
+    /** MUST use init() function if this constructor is used. */
+    PipelineStage() { }
+
+    virtual ~PipelineStage() { }
+
+    /** PipelineStage initialization. */
+    void init(Params *params, unsigned stage_num);
+
+    /** Returns the name of stage. */
+    std::string name() const;
+
+    /** Registers statistics. */
+    void regStats();
+
+    /** Sets CPU pointer. */
+    virtual void setCPU(InOrderCPU *cpu_ptr);
+
+    virtual void scheduleStageStart(int delay, int tid) { }
+
+    /** Sets the main backwards communication time buffer pointer. */
+    void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+    /** Sets pointer to time buffer coming from fetch. */
+    void setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr);
+
+    /** Sets pointer to time buffer used to communicate to the next stage. */
+    void setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr);
+
+    /** Sets pointer to list of active threads. */
+    void setActiveThreads(std::list<unsigned> *at_ptr);
+
+    bool nextStageQueueValid(int stage_num);
+
+    bool isBlocked(unsigned tid);
+
+    /** Changes the status of this stage to active, and indicates this
+     * to the CPU.
+     */
+    //inline void switchToActive();
+
+    /** Changes the status of this stage to inactive, and indicates
+     * this to the CPU.
+     */
+    //inline void switchToInactive();
+
+    /** Switches out the stage stage. */
+    void switchOut();
+
+    /** Takes over from another CPU's thread. */
+    void takeOverFrom();
+
+    /** Ticks stage, processing all input signals and executing as many
+     *  instructions as possible.
+     */
+    virtual void tick();
+
+    /** Is out of order processing valid? */
+    bool outOfOrderValid();
+
+    /** Set a resource stall in the pipeline-stage */
+    void setResStall(ResReqPtr res_req, unsigned tid);
+
+    /** Unset a resource stall in the pipeline-stage */
+    void unsetResStall(ResReqPtr res_req, unsigned tid);
+
+    /** Remove all stall signals for a particular thread; */
+    virtual void removeStalls(unsigned tid);
+
+    /** Is there room in the stage buffer? */
+    int stageBufferAvail();
+
+  protected:
+    /** Evaluate Stage Conditions and then process stage */
+    virtual void processStage(bool &status_change);
+
+    /** Determines what to do based on stage's current status.
+     * @param status_change stage() sets this variable if there was a status
+     * change (ie switching from from blocking to unblocking).
+     * @param tid Thread id to stage instructions from.
+     */
+    virtual void processThread(bool &status_change, unsigned tid);
+
+    /** Processes instructions from fetch and passes them on to rename.
+     * Decoding of instructions actually happens when they are created in
+     * fetch, so this function mostly checks if PC-relative branches are
+     * correct.
+     */
+    virtual void processInsts(unsigned tid);
+
+    /** Process all resources on an instruction's resource schedule */
+    virtual bool processInstSchedule(DynInstPtr inst);
+
+    /** Is there room in the next stage buffer for this instruction? */
+    virtual bool canSendInstToNextStage();
+
+    /** Send an instruction to the next stage buffer */
+    virtual bool sendInstToNextStage(DynInstPtr inst);
+
+    /** Inserts a thread's instructions into the skid buffer, to be staged
+     * once stage unblocks.
+     */
+    virtual void skidInsert(unsigned tid);
+
+    /** Returns if all of the skid buffers are empty. */
+    bool skidsEmpty();
+
+    /** Updates overall stage status based on all of the threads' statuses. */
+    virtual void updateStatus();
+
+    /** Separates instructions from fetch into individual lists of instructions
+     * sorted by thread.
+     */
+    void sortInsts();
+
+    /** Reads all stall signals from the backwards communication timebuffer. */
+    virtual void readStallSignals(unsigned tid);
+
+    /** Checks all input signals and updates stage's status appropriately. */
+    virtual bool checkSignalsAndUpdate(unsigned tid);
+
+    /** Checks all stall signals, and returns if any are true. */
+    virtual bool checkStall(unsigned tid) const;
+
+    /** Returns if there any instructions from the previous stage
+     * on this cycle.
+     */
+    inline bool prevStageInstsValid();
+
+    /** Switches stage to blocking, and signals back that stage has
+     * become blocked.
+     * @return Returns true if there is a status change.
+     */
+    virtual bool block(unsigned tid);
+
+    void blockDueToBuffer(unsigned tid);
+
+    /** Switches stage to unblocking if the skid buffer is empty, and
+     * signals back that stage has unblocked.
+     * @return Returns true if there is a status change.
+     */
+    virtual bool unblock(unsigned tid);
+
+
+  public:
+    /** Squashes if there is a PC-relative branch that was predicted
+     * incorrectly. Sends squash information back to fetch.
+     */
+    virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid);
+
+    /** Squash instructions from stage buffer  */
+    virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid);
+
+    /** Squashes due to commit signalling a squash. Changes status to
+     *  squashing and clears block/unblock signals as needed.
+     */
+    virtual void squash(InstSeqNum squash_num, unsigned tid);
+
+    void dumpInsts();
+
+  protected:
+    /** CPU interface. */
+    InOrderCPU *cpu;
+
+    Trace::InOrderTrace *tracer;
+
+    /** List of active thread ids */
+    std::list<unsigned> *activeThreads;
+
+    /** Queue of all instructions coming from previous stage on this cycle. */
+    std::queue<DynInstPtr> insts[ThePipeline::MaxThreads];
+
+    /** Queue of instructions that are finished processing and ready to go next stage.
+     *  This is used to prevent from processing an instrution more than once on any
+     *  stage. NOTE: It is up to the PROGRAMMER must manage this as a queue
+     */
+    std::list<DynInstPtr> instsToNextStage;
+
+    /** Skid buffer between previous stage and this one. */
+    std::queue<DynInstPtr> skidBuffer[ThePipeline::MaxThreads];
+
+    /** Instruction used to signify that there is no *real* instruction in buffer slot */
+    DynInstPtr dummyBufferInst;
+
+    /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */
+    Addr bdelayDoneSeqNum[ThePipeline::MaxThreads];
+
+    /** Instruction used for squashing branch (used for MIPS) */
+    DynInstPtr squashInst[ThePipeline::MaxThreads];
+
+    /** Tells when their is a pending delay slot inst. to send
+     *  to rename. If there is, then wait squash after the next
+     *  instruction (used for MIPS).
+     */
+    bool squashAfterDelaySlot[ThePipeline::MaxThreads];
+
+    /** Maximum size of the inter-stage buffer connecting the previous stage to
+     *  this stage (which we call a skid buffer) */
+    unsigned stageBufferMax;
+
+    /** Variable that tracks if stage has written to the time buffer this
+     * cycle. Used to tell CPU if there is activity this cycle.
+     */
+    bool wroteToTimeBuffer;
+
+    /** Index of instructions being sent to the next stage. */
+    unsigned toNextStageIndex;
+
+    /** The last stage that this particular stage should look for stalls */
+    int lastStallingStage[ThePipeline::MaxThreads];
+
+    /** Time buffer interface. */
+    TimeBuffer<TimeStruct> *timeBuffer;
+
+  public:
+    /** Wire to get rename's output from backwards time buffer. */
+    TimeBuffer<TimeStruct>::wire fromNextStages;
+
+    /** Wire to get iew's information from backwards time buffer. */
+    TimeBuffer<TimeStruct>::wire toPrevStages;
+
+    /** Instruction queue linking previous stage */
+    TimeBuffer<InterStageStruct> *prevStageQueue;
+
+    /** Wire to get the previous stage's. */
+    TimeBuffer<InterStageStruct>::wire prevStage;
+
+    /** Instruction queue linking next stage */
+    TimeBuffer<InterStageStruct> *nextStageQueue;
+
+    /** Wire to write to the next stage */
+    TimeBuffer<InterStageStruct>::wire nextStage;
+
+    /** Is Previous Stage Valid? */
+    bool prevStageValid;
+
+    /** Is Next Stage Valid? */
+    bool nextStageValid;
+
+    /** Source of possible stalls. */
+    struct Stalls {
+        bool stage[ThePipeline::NumStages];
+        std::vector<ResReqPtr> resources;
+    };
+
+    /** Tracks which stages are telling decode to stall. */
+    Stalls stalls[ThePipeline::MaxThreads];
+
+    //@TODO: Use Stats for the pipeline stages
+    /** Stat for total number of idle cycles. */
+    //Stats::Scalar<> stageIdleCycles;
+    /** Stat for total number of blocked cycles. */
+    //Stats::Scalar<> stageBlockedCycles;
+    /** Stat for total number of normal running cycles. */
+    //Stats::Scalar<> stageRunCycles;
+    /** Stat for total number of unblocking cycles. */
+    //Stats::Scalar<> stageUnblockCycles;
+    /** Stat for total number of squashing cycles. */
+    //Stats::Scalar<> stageSquashCycles;
+    /** Stat for total number of staged instructions. */
+    //Stats::Scalar<> stageProcessedInsts;
+    /** Stat for total number of squashed instructions. */
+    //Stats::Scalar<> stageSquashedInsts;
+};
+
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.5stage.cc b/src/cpu/inorder/pipeline_traits.5stage.cc
new file mode 100644 (file)
index 0000000..50c30af
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+    int cur_pri = 20;
+
+    /*
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_it = inst->resSched.begin();
+
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_end = inst->resSched.end();
+
+    while (sked_it != sked_end) {
+
+        if (sked_it.top()->stageNum == stage_num) {
+            cur_pri = sked_it.top()->priority;
+        }
+
+        sked_it++;
+    }
+    */
+
+    return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+    int stNum = 0;
+    int stPri = 0;
+    // Get Pointer to Instuction's Schedule
+    ResSchedule *inst_sched = &inst->resSched;
+
+    //
+    // IF - Stage 0
+    // ---------------------------------------
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::AssignNextPC));
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, ITLB,     TLBUnit::FetchLookup));
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache,   CacheUnit::InitiateFetch));
+
+    //
+    // DE - Stage 1
+    // ---------------------------------------
+    stNum++; stPri = 0;
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache,   CacheUnit::CompleteFetch));
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, Decode,   DecodeUnit::DecodeInst));
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, BPred,    BranchPredictor::PredictBranch));
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::UpdateTargetPC));
+
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+    if (!inst->staticInst) {
+        return false;
+    }
+
+    int stNum = BackEndStartStage;
+    int stPri = 0;
+
+    // Get Pointer to Instuction's Schedule
+    ResSchedule *inst_sched = &inst->resSched;
+
+    //
+    // EX - Stage 2
+    // ---------------------------------------
+    for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+        if (!idx || !inst->isStore())
+            inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, idx));
+    }
+
+    if ( inst->isNonSpeculative() ) {
+        // skip execution of non speculative insts until later
+    } else if (inst->isMemRef()) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, AGEN, AGENUnit::GenerateAddr));
+        if ( inst->isLoad() ) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup));
+            inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateReadData));
+        }
+    } else {
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst));
+    }
+
+    //
+    // MEM - Stage 3
+    // ---------------------------------------
+    stPri = 0; stNum++;
+    if ( inst->isStore() ) { // for store, need src reg at this point
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, 1));
+    }
+    if ( inst->isLoad() ) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteReadData));
+    } else if ( inst->isStore() ) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup));
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateWriteData));
+    }
+
+    //
+    // WB - Stage 4
+    // ---------------------------------------
+    stPri = 0; stNum++;
+    if (inst->isNonSpeculative()) {
+        if (inst->isMemRef())
+            fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
+
+        if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
+        } else {
+            inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst));
+        }
+    }
+
+    if ( inst->isStore() )
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteWriteData));
+
+    // Write Back to Register File
+    for (int idx=0; idx < inst->numDestRegs(); idx++) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::WriteDestReg, idx));
+    }
+
+    // Graduate Instructions
+    inst_sched->push(new ScheduleEntry(stNum, stPri++, Grad, GraduationUnit::GraduateInst));
+
+    return true;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.5stage.hh b/src/cpu/inorder/pipeline_traits.5stage.hh
new file mode 100644 (file)
index 0000000..aea6eff
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/params.hh"
+
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+    // Pipeline Constants
+    const unsigned NumStages = 5;
+    const unsigned MaxThreads = 3;
+    const unsigned StageWidth = 1;
+    const unsigned BackEndStartStage = 2;
+
+    // Enumerated List of Resources The Pipeline Uses
+    enum ResourceList {
+       FetchSeq = 0,
+       ITLB,
+       ICache,
+       Decode,
+       BPred,
+       FetchBuff,
+       RegManager,
+       AGEN,
+       ExecUnit,
+       DTLB,
+       DCache,
+       Grad,
+       FetchBuff2
+    };
+
+    // Expand this as necessary for your inter stage buffer sizes
+    static const unsigned interStageBuffSize[] = {
+        StageWidth, /* Stage 0 - 1 */
+        StageWidth, /* Stage 1 - 2 */
+        StageWidth, /* Stage 2 - 3 */
+        StageWidth, /* Stage 3 - 4 */
+        StageWidth, /* Stage 4 - 5 */
+        StageWidth, /* Stage 5 - 6 */
+        StageWidth, /* Stage 6 - 7 */
+        StageWidth, /* Stage 7 - 8 */
+        StageWidth  /* Stage 8 - 9 */
+    };
+
+    typedef InOrderCPUParams Params;
+    typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+    //////////////////////////
+    // RESOURCE SCHEDULING
+    //////////////////////////
+    struct ScheduleEntry {
+        ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+                      int _idx = 0) :
+            stageNum(stage_num), resNum(res_num), cmd(_cmd),
+            idx(_idx), priority(_priority)
+        { }
+        virtual ~ScheduleEntry(){}
+
+        // Stage number to perform this service.
+        int stageNum;
+
+        // Resource ID to access
+        int resNum;
+
+        // See specific resource for meaning
+        unsigned cmd;
+
+        // See specific resource for meaning
+        unsigned idx;
+
+        // Some Resources May Need Priority?
+        int priority;
+    };
+
+    struct entryCompare {
+        bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+        {
+            // Prioritize first by stage number that the resource is needed
+            if (lhs->stageNum > rhs->stageNum) {
+                return true;
+            } else if (lhs->stageNum == rhs->stageNum) {
+                /*if (lhs->resNum > rhs->resNum) {
+                  return true;
+                } else {
+                  return false;
+                  }*/
+
+                if (lhs->priority > rhs->priority) {
+                  return true;
+                } else {
+                  return false;
+                }
+            } else {
+                return false;
+            }
+        }
+    };
+
+
+    typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+                                         entryCompare> ResSchedule;
+
+    void createFrontEndSchedule(DynInstPtr &inst);
+    bool createBackEndSchedule(DynInstPtr &inst);
+    int getNextPriority(DynInstPtr &inst, int stage_num);
+};
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.9stage.cc b/src/cpu/inorder/pipeline_traits.9stage.cc
new file mode 100644 (file)
index 0000000..d686bb3
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * 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/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+    int cur_pri = 20;
+
+    /*
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_it = inst->resSched.begin();
+
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_end = inst->resSched.end();
+
+    while (sked_it != sked_end) {
+
+        if (sked_it.top()->stageNum == stage_num) {
+            cur_pri = sked_it.top()->priority;
+        }
+
+        sked_it++;
+    }
+    */
+
+    return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+    int stNum = 0;
+    int stPri = 0;
+    // Get Pointer to Instuction's Schedule
+    ResSchedule *inst_sched = &inst->resSched;
+
+    //
+    // Stage 0
+    // ---------------------------------------
+    inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch));
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stNum++;
+    stPri = 0;
+
+    //
+    // Stage 1
+    // ---------------------------------------
+    inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC));
+    stPri++;
+
+    if (inst->readTid() == 0)
+        inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff, InstBuffer::ScheduleOrBypass));
+    else //if (inst->readTid() == 1)
+        inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff2, InstBuffer::ScheduleOrBypass));
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stNum++;
+    stPri = 0;
+
+    //
+    // Stage 2
+    // ---------------------------------------
+    // Reset Priority / Update Next Stage Number
+    stNum++;
+    stPri = 0;
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+    if (!inst->staticInst) {
+        return false;
+    }
+
+    std::string name = inst->staticInst->getName();
+
+    int stNum = BackEndStartStage;
+    int stPri = 0;
+
+    // Get Pointer to Instuction's Schedule
+    ResSchedule *inst_sched = &inst->resSched;
+
+    //
+    // Stage 3
+    // ---------------------------------------
+    // Set When Source Registers Should be read - Stage 4
+    for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx));
+    }
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 4
+    // ---------------------------------------
+    if (inst->isMemRef()) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr));
+    }
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 5
+    // ---------------------------------------
+    // Execution Unit
+    if (!inst->isNonSpeculative() && !inst->isMemRef()) {
+        if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
+        } else {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+        }
+    }
+    stPri++;
+
+    // DCache Initiate Access
+    if (inst->isMemRef()) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup));
+        stPri++;
+
+        if (inst->isLoad()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData));
+        } else if (inst->isStore()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData));
+        }
+    }
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 6
+    // ---------------------------------------
+    // DCache Complete Access
+    if (inst->isMemRef()) {
+        if (inst->isLoad()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData));
+        } else if (inst->isStore()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData));
+        }
+    }
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 7
+    // ---------------------------------------
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 8
+    // ---------------------------------------
+    // NonSpeculative Execution
+    if (inst->isNonSpeculative() ) {
+        if (inst->isMemRef())
+            fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
+
+        inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+        stPri++;
+    }
+
+    // Write Back to Register File
+    for (int idx=0; idx < inst->numDestRegs(); idx++) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx));
+        stPri++;
+    }
+
+    // Graduate Instructions
+    inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst));
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    return true;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.9stage.hh b/src/cpu/inorder/pipeline_traits.9stage.hh
new file mode 100644 (file)
index 0000000..91e5373
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+#include <map>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/params.hh"
+
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+    // Pipeline Constants
+    const unsigned NumStages = 9;
+    const unsigned MaxThreads = 3;
+    const unsigned StageWidth = 2;
+    const unsigned BackEndStartStage = 3;
+
+    // Use this to over-ride default stage widths
+    static std::map<unsigned, unsigned> stageBufferSizes;
+
+    //static unsigned interStageBuffSize[NumStages];
+
+    static const unsigned interStageBuffSize[NumStages] = {
+        StageWidth, /* Stage 0 - 1 */
+        StageWidth, /* Stage 1 - 2 */
+        4,          /* Stage 2 - 3 */
+        StageWidth, /* Stage 3 - 4 */
+        StageWidth, /* Stage 4 - 5 */
+        StageWidth, /* Stage 5 - 6 */
+        StageWidth, /* Stage 6 - 7 */
+        StageWidth, /* Stage 7 - 8 */
+        StageWidth  /* Stage 8 - 9 */
+    };
+
+
+    // Enumerated List of Resources The Pipeline Uses
+    enum ResourceList {
+       FetchSeq = 0,
+       ITLB,
+       ICache,
+       Decode,
+       BPred,
+       FetchBuff,
+       RegManager,
+       AGEN,
+       ExecUnit,
+       DTLB,
+       DCache,
+       Grad,
+       FetchBuff2
+    };
+
+    typedef InOrderCPUParams Params;
+    typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+//void initPipelineTraits();
+
+    //////////////////////////
+    // RESOURCE SCHEDULING
+    //////////////////////////
+    struct ScheduleEntry {
+        ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+                      int _idx = 0) :
+            stageNum(stage_num), resNum(res_num), cmd(_cmd),
+            idx(_idx), priority(_priority)
+        { }
+        virtual ~ScheduleEntry(){}
+
+        // Stage number to perform this service.
+        int stageNum;
+
+        // Resource ID to access
+        int resNum;
+
+        // See specific resource for meaning
+        unsigned cmd;
+
+        // See specific resource for meaning
+        unsigned idx;
+
+        // Some Resources May Need Priority?
+        int priority;
+    };
+
+    struct entryCompare {
+        bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+        {
+            // Prioritize first by stage number that the resource is needed
+            if (lhs->stageNum > rhs->stageNum) {
+                return true;
+            } else if (lhs->stageNum == rhs->stageNum) {
+                /*if (lhs->resNum > rhs->resNum) {
+                  return true;
+                } else {
+                  return false;
+                  }*/
+
+                if (lhs->priority > rhs->priority) {
+                  return true;
+                } else {
+                  return false;
+                }
+            } else {
+                return false;
+            }
+        }
+    };
+
+
+    typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+                                         entryCompare> ResSchedule;
+
+    void createFrontEndSchedule(DynInstPtr &inst);
+    bool createBackEndSchedule(DynInstPtr &inst);
+    int getNextPriority(DynInstPtr &inst, int stage_num);
+};
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.cc b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
new file mode 100644 (file)
index 0000000..9d2ed8e
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * 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/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+    int cur_pri = 20;
+
+    /*
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_it = inst->resSched.begin();
+
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_end = inst->resSched.end();
+
+    while (sked_it != sked_end) {
+
+        if (sked_it.top()->stageNum == stage_num) {
+            cur_pri = sked_it.top()->priority;
+        }
+
+        sked_it++;
+    }
+    */
+
+    return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+    int stNum = 0;
+    int stPri = 0;
+    // Get Pointer to Instuction's Schedule
+    ResSchedule *inst_sched = &inst->resSched;
+
+    //
+    // Stage 0
+    // ---------------------------------------
+    inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch));
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stNum++;
+    stPri = 0;
+
+    //
+    // Stage 1
+    // ---------------------------------------
+    inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch));
+    stPri++;
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC));
+    stPri++;
+
+    int fetch_buff_num = FetchBuff + inst->readTid();
+
+    inst_sched->push(new ScheduleEntry(stNum, stPri, fetch_buff_num, InstBuffer::ScheduleOrBypass));
+
+    // Reset Priority / Update Next Stage Number
+    stNum++;
+    stPri = 0;
+
+    //
+    // Stage 2
+    // ---------------------------------------
+    // Reset Priority / Update Next Stage Number
+    stNum++;
+    stPri = 0;
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+    if (!inst->staticInst) {
+        return false;
+    }
+
+    std::string name = inst->staticInst->getName();
+
+    int stNum = BackEndStartStage;
+    int stPri = 0;
+
+    // Get Pointer to Instuction's Schedule
+    ResSchedule *inst_sched = &inst->resSched;
+
+    //
+    // Stage 3
+    // ---------------------------------------
+    // Set When Source Registers Should be read - Stage 4
+    for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx));
+    }
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 4
+    // ---------------------------------------
+    if (inst->isMemRef()) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr));
+    }
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 5
+    // ---------------------------------------
+    // Execution Unit
+    if (!inst->isNonSpeculative() && !inst->isMemRef()) {
+        //if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+            //inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
+            //} else {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+            //}
+    }
+    stPri++;
+
+    // DCache Initiate Access
+    if (inst->isMemRef()) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup));
+        stPri++;
+
+        if (inst->isLoad()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData));
+        } else if (inst->isStore()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData));
+        }
+    }
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 6
+    // ---------------------------------------
+    // DCache Complete Access
+    if (inst->isMemRef()) {
+        if (inst->isLoad()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData));
+        } else if (inst->isStore()) {
+            inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData));
+        }
+    }
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 7
+    // ---------------------------------------
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    //
+    // Stage 8
+    // ---------------------------------------
+    // NonSpeculative Execution
+    if (inst->isNonSpeculative() ) {
+        if (inst->isMemRef())
+            fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
+
+        inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+        stPri++;
+    }
+
+    // Write Back to Register File
+    for (int idx=0; idx < inst->numDestRegs(); idx++) {
+        inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx));
+        stPri++;
+    }
+
+    // Graduate Instructions
+    inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst));
+    stPri++;
+
+    // Reset Priority / Update Next Stage Number
+    stPri = 0;
+    stNum++;
+
+    return true;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.hh b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
new file mode 100644 (file)
index 0000000..22da4ea
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+#include <map>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/params.hh"
+
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+    // Pipeline Constants
+    const unsigned NumStages = 9;
+    const unsigned MaxThreads = 2;
+    const unsigned StageWidth = 1;
+    const unsigned BackEndStartStage = 3;
+
+    // Use this to over-ride default stage widths
+    static std::map<unsigned, unsigned> stageBufferSizes;
+
+    //static unsigned interStageBuffSize[NumStages];
+
+    static const unsigned interStageBuffSize[NumStages] = {
+        StageWidth, /* Stage 0 - 1 */
+        StageWidth, /* Stage 1 - 2 */
+        MaxThreads * 4,          /* Stage 2 - 3 */
+        StageWidth, /* Stage 3 - 4 */
+        MaxThreads * 4, /* Stage 4 - 5 */
+        StageWidth, /* Stage 5 - 6 */
+        StageWidth, /* Stage 6 - 7 */
+        StageWidth, /* Stage 7 - 8 */
+        MaxThreads  /* Stage 8 - 9 */
+    };
+
+
+    // Enumerated List of Resources The Pipeline Uses
+    enum ResourceList {
+       FetchSeq = 0,
+       ITLB,
+       ICache,
+       Decode,
+       BPred,
+       RegManager,
+       AGEN,
+       ExecUnit,
+       DTLB,
+       DCache,
+       Grad,
+       FetchBuff,
+       FetchBuff2
+    };
+
+    typedef InOrderCPUParams Params;
+    typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+//void initPipelineTraits();
+
+    //////////////////////////
+    // RESOURCE SCHEDULING
+    //////////////////////////
+    struct ScheduleEntry {
+        ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+                      int _idx = 0) :
+            stageNum(stage_num), resNum(res_num), cmd(_cmd),
+            idx(_idx), priority(_priority)
+        { }
+        virtual ~ScheduleEntry(){}
+
+        // Stage number to perform this service.
+        int stageNum;
+
+        // Resource ID to access
+        int resNum;
+
+        // See specific resource for meaning
+        unsigned cmd;
+
+        // See specific resource for meaning
+        unsigned idx;
+
+        // Some Resources May Need Priority?
+        int priority;
+    };
+
+    struct entryCompare {
+        bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+        {
+            // Prioritize first by stage number that the resource is needed
+            if (lhs->stageNum > rhs->stageNum) {
+                return true;
+            } else if (lhs->stageNum == rhs->stageNum) {
+                /*if (lhs->resNum > rhs->resNum) {
+                  return true;
+                } else {
+                  return false;
+                  }*/
+
+                if (lhs->priority > rhs->priority) {
+                  return true;
+                } else {
+                  return false;
+                }
+            } else {
+                return false;
+            }
+        }
+    };
+
+
+    typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+                                         entryCompare> ResSchedule;
+
+    void createFrontEndSchedule(DynInstPtr &inst);
+    bool createBackEndSchedule(DynInstPtr &inst);
+    int getNextPriority(DynInstPtr &inst, int stage_num);
+};
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc
new file mode 100644 (file)
index 0000000..eb89945
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+    int cur_pri = 20;
+
+    /*
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_it = inst->resSched.begin();
+
+    std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+        entryCompare>::iterator sked_end = inst->resSched.end();
+
+    while (sked_it != sked_end) {
+
+        if (sked_it.top()->stageNum == stage_num) {
+            cur_pri = sked_it.top()->priority;
+        }
+
+        sked_it++;
+    }
+    */
+
+    return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+    InstStage *I = inst->addStage();
+    InstStage *E = inst->addStage();
+
+    I->needs(FetchSeq, FetchSeqUnit::AssignNextPC);
+    I->needs(ITLB, TLBUnit::FetchLookup);
+    I->needs(ICache, CacheUnit::InitiateFetch);
+
+    E->needs(ICache, CacheUnit::CompleteFetch);
+    E->needs(Decode, DecodeUnit::DecodeInst);
+    E->needs(BPred, BranchPredictor::PredictBranch);
+    E->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC);
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+    if (!inst->staticInst) {
+        return false;
+    }
+
+    InstStage *E = inst->currentStage();
+    InstStage *M = inst->addStage();
+    InstStage *A = inst->addStage();
+    InstStage *W = inst->addStage();
+
+    for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+        if (!idx || !inst->isStore()) {
+            E->needs(RegManager, UseDefUnit::ReadSrcReg, idx);
+        }
+    }
+
+
+    if ( inst->isNonSpeculative() ) {
+        // skip execution of non speculative insts until later
+    } else if ( inst->isMemRef() ) {
+        E->needs(AGEN, AGENUnit::GenerateAddr);
+        if ( inst->isLoad() ) {
+            E->needs(DTLB, TLBUnit::DataLookup);
+            E->needs(DCache, CacheUnit::InitiateReadData);
+        }
+    } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+        E->needs(MDU, MultDivUnit::StartMultDiv);
+
+        // ZERO-LATENCY Multiply:
+        // E->needs(MDU, MultDivUnit::MultDiv);
+    } else {
+        E->needs(ExecUnit, ExecutionUnit::ExecuteInst);
+    }
+
+    if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+        M->needs(MDU, MultDivUnit::EndMultDiv);
+    }
+
+    if ( inst->isLoad() ) {
+        M->needs(DCache, CacheUnit::CompleteReadData);
+    } else if ( inst->isStore() ) {
+        M->needs(RegManager, UseDefUnit::ReadSrcReg, 1);
+        M->needs(DTLB, TLBUnit::DataLookup);
+        M->needs(DCache, CacheUnit::InitiateWriteData);
+    }
+
+    if ( inst->isStore() ) {
+        A->needs(DCache, CacheUnit::CompleteWriteData);
+    }
+
+    if ( inst->isNonSpeculative() ) {
+        if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction");
+        W->needs(ExecUnit, ExecutionUnit::ExecuteInst);
+    }
+
+    for (int idx=0; idx < inst->numDestRegs(); idx++) {
+        W->needs(RegManager, UseDefUnit::WriteDestReg, idx);
+    }
+
+    W->needs(Grad, GraduationUnit::GraduateInst);
+
+    return true;
+}
+
+InstStage::InstStage(DynInstPtr inst, int stage_num)
+{
+    stageNum = stage_num;
+    nextTaskPriority = 0;
+    instSched = &inst->resSched;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh
new file mode 100644 (file)
index 0000000..c5e4bb2
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/base.hh"
+//#include "cpu/inorder/params.hh"
+
+#include "params/InOrderCPU.hh"
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+    // Pipeline Constants
+    const unsigned NumStages = 5;
+    const unsigned MaxThreads = 8;
+    const unsigned StageWidth = 1;
+    const unsigned BackEndStartStage = 2;
+
+    // Enumerated List of Resources The Pipeline Uses
+    enum ResourceList {
+       FetchSeq = 0,
+       ITLB,
+       ICache,
+       Decode,
+       BPred,
+       FetchBuff,
+       RegManager,
+       AGEN,
+       ExecUnit,
+       MDU,
+       DTLB,
+       DCache,
+       Grad,
+       FetchBuff2
+    };
+
+    // Expand this as necessary for your inter stage buffer sizes
+    static const unsigned interStageBuffSize[] = {
+        StageWidth, /* Stage 0 - 1 */
+        StageWidth, /* Stage 1 - 2 */
+        StageWidth, /* Stage 2 - 3 */
+        StageWidth, /* Stage 3 - 4 */
+        StageWidth, /* Stage 4 - 5 */
+        StageWidth, /* Stage 5 - 6 */
+        StageWidth, /* Stage 6 - 7 */
+        StageWidth, /* Stage 7 - 8 */
+        StageWidth  /* Stage 8 - 9 */
+    };
+
+    typedef InOrderCPUParams Params;
+    typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+    //////////////////////////
+    // RESOURCE SCHEDULING
+    //////////////////////////
+    struct ScheduleEntry {
+        ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+                      int _idx = 0) :
+            stageNum(stage_num), resNum(res_num), cmd(_cmd),
+            idx(_idx), priority(_priority)
+        { }
+        virtual ~ScheduleEntry(){}
+
+        // Stage number to perform this service.
+        int stageNum;
+
+        // Resource ID to access
+        int resNum;
+
+        // See specific resource for meaning
+        unsigned cmd;
+
+        // See specific resource for meaning
+        unsigned idx;
+
+        // Some Resources May Need Priority?
+        int priority;
+    };
+
+    struct entryCompare {
+        bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+        {
+            // Prioritize first by stage number that the resource is needed
+            if (lhs->stageNum > rhs->stageNum) {
+                return true;
+            } else if (lhs->stageNum == rhs->stageNum) {
+                /*if (lhs->resNum > rhs->resNum) {
+                  return true;
+                } else {
+                  return false;
+                  }*/
+
+                if (lhs->priority > rhs->priority) {
+                  return true;
+                } else {
+                  return false;
+                }
+            } else {
+                return false;
+            }
+        }
+    };
+
+
+    typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+                                         entryCompare> ResSchedule;
+
+    void createFrontEndSchedule(DynInstPtr &inst);
+    bool createBackEndSchedule(DynInstPtr &inst);
+    int getNextPriority(DynInstPtr &inst, int stage_num);
+
+    class InstStage {
+      private:
+        int nextTaskPriority;
+        int stageNum;
+        ResSchedule *instSched;
+
+      public:
+        InstStage(DynInstPtr inst, int stage_num);
+
+        void needs(int unit, int request) {
+            instSched->push( new ScheduleEntry(
+                stageNum, nextTaskPriority++, unit, request
+            ));
+        }
+
+        void needs(int unit, int request, int param) {
+            instSched->push( new ScheduleEntry(
+                stageNum, nextTaskPriority++, unit, request, param
+            ));
+        }
+
+    };
+};
+
+
+
+
+#endif
diff --git a/src/cpu/inorder/reg_dep_map.cc b/src/cpu/inorder/reg_dep_map.cc
new file mode 100644 (file)
index 0000000..a405b1f
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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 "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+RegDepMap::RegDepMap(int size)
+{
+    regMap.resize(size);
+}
+
+string
+RegDepMap::name()
+{
+    return cpu->name() + ".RegDepMap";
+}
+
+void
+RegDepMap::setCPU(InOrderCPU *_cpu)
+{
+    cpu = _cpu;
+}
+
+void
+RegDepMap::clear()
+{
+    regMap.clear();
+}
+
+void
+RegDepMap::insert(DynInstPtr inst)
+{
+    int dest_regs = inst->numDestRegs();
+
+    DPRINTF(RegDepMap, "Setting Output Dependencies for [sn:%i] "
+            ", %s (dest. regs = %i).\n",
+            inst->seqNum,
+            inst->staticInst->getName(),
+            dest_regs);
+
+    for (int i = 0; i < dest_regs; i++) {
+        int idx = inst->destRegIdx(i);
+
+        //if (inst->numFPDestRegs())
+        //  idx += TheISA::FP_Base_DepTag;
+
+        insert(idx, inst);
+    }
+}
+
+
+void
+RegDepMap::insert(unsigned idx, DynInstPtr inst)
+{
+    DPRINTF(RegDepMap, "Inserting [sn:%i] onto dep. list for reg. idx %i.\n",
+            inst->seqNum, idx);
+
+    regMap[idx].push_back(inst);
+
+    inst->setRegDepEntry();
+}
+
+void
+RegDepMap::remove(DynInstPtr inst)
+{
+    if (inst->isRegDepEntry()) {
+        DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map.\n",
+                inst->seqNum);
+
+        int dest_regs = inst->numDestRegs();
+
+        for (int i = 0; i < dest_regs; i++) {
+            int idx = inst->destRegIdx(i);
+            remove(idx, inst);
+        }
+    }
+}
+
+void
+RegDepMap::remove(unsigned idx, DynInstPtr inst)
+{
+    std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+    std::list<DynInstPtr>::iterator list_end = regMap[idx].end();
+
+    while (list_it != list_end) {
+        if((*list_it) == inst) {
+            regMap[idx].erase(list_it);
+            break;
+        }
+
+        list_it++;
+    }
+}
+
+void
+RegDepMap::removeFront(unsigned idx, DynInstPtr inst)
+{
+   std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+   DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on phys. reg."
+           "%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum);
+
+   assert(list_it != regMap[idx].end());
+
+   assert(inst == (*list_it));
+
+   regMap[idx].erase(list_it);
+}
+
+bool
+RegDepMap::canRead(unsigned idx, DynInstPtr inst)
+{
+    if (regMap[idx].size() == 0)
+        return true;
+
+    std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+    if (inst->seqNum <= (*list_it)->seqNum) {
+        return true;
+    } else {
+        DPRINTF(RegDepMap, "[sn:%i] Can't read from RegFile, [sn:%i] has not written"
+                " it's value back yet.\n",  inst->seqNum, (*list_it)->seqNum);
+        return false;
+    }
+}
+
+ThePipeline::DynInstPtr
+RegDepMap::canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst)
+{
+    std::list<DynInstPtr>::iterator list_it = regMap[reg_idx].begin();
+    std::list<DynInstPtr>::iterator list_end = regMap[reg_idx].end();
+
+    DynInstPtr forward_inst = NULL;
+
+    // Look for first, oldest instruction
+    while (list_it != list_end &&
+           (*list_it)->seqNum < inst->seqNum) {
+        forward_inst = (*list_it);
+        list_it++;
+    }
+
+    if (forward_inst) {
+        if (forward_inst->isExecuted() &&
+            forward_inst->readResultTime(src_idx) < curTick) {
+            return forward_inst;
+        } else {
+            DPRINTF(RegDepMap, "[sn:%i] Can't get value through forwarding, "
+                    " [sn:%i] has not been executed yet.\n",
+                    inst->seqNum, forward_inst->seqNum);
+            return NULL;
+        }
+    } else {
+        DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n",
+                inst->seqNum);
+        return NULL;
+    }
+}
+
+bool
+RegDepMap::canWrite(unsigned idx, DynInstPtr inst)
+{
+    if (regMap[idx].size() == 0)
+        return true;
+
+    std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+    if (inst->seqNum <= (*list_it)->seqNum) {
+        return true;
+    } else {
+        DPRINTF(RegDepMap, "[sn:%i] Can't write from RegFile: [sn:%i] has not written"
+                " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum);
+    }
+
+    return false;
+}
+
+int
+RegDepMap::depSize(unsigned idx)
+{
+    return regMap[idx].size();
+}
+
+ThePipeline::DynInstPtr
+RegDepMap::findBypassInst(unsigned idx)
+{
+    std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+    if (depSize(idx) == 1)
+        return NULL;
+
+    list_it++;
+
+    while (list_it != regMap[idx].end()) {
+        if((*list_it)->isExecuted()) {
+            return *list_it;
+            break;
+        }
+    }
+
+    return NULL;
+}
diff --git a/src/cpu/inorder/reg_dep_map.hh b/src/cpu/inorder/reg_dep_map.hh
new file mode 100644 (file)
index 0000000..ba2a8c8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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_REG_DEP_MAP_HH
+#define CPU_INORDER_REG_DEP_MAP_HH
+
+#include <list>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+class InOrderCPU;
+
+class RegDepMap
+{
+    typedef ThePipeline::DynInstPtr DynInstPtr;
+
+  public:
+    RegDepMap(int size = TheISA::TotalNumRegs);
+
+    ~RegDepMap() { }
+
+    std::string name();
+
+    void setCPU(InOrderCPU *_cpu);
+
+    /** Clear the Entire Map */
+    void clear();
+
+    /** Insert all of a instruction's destination registers into map*/
+    void insert(DynInstPtr inst);
+
+    /** Insert an instruction into a specific destination register index onto map */
+    void insert(unsigned idx, DynInstPtr inst);
+
+    /** Remove all of a instruction's destination registers into map*/
+    void remove(DynInstPtr inst);
+
+    /** Remove a specific instruction and destination register index from map */
+    void remove(unsigned idx, DynInstPtr inst);
+
+    /** Remove Front instruction from a destination register */
+    void removeFront(unsigned idx, DynInstPtr inst);
+
+    /** Is the current instruction able to read from this destination register? */
+    bool canRead(unsigned idx, DynInstPtr inst);
+
+    /** Is the current instruction able to get a forwarded value from another instruction
+     *  for this destination register? */
+    DynInstPtr canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst);
+
+    /** find an instruction to forward/bypass a value from */
+    DynInstPtr findBypassInst(unsigned idx);
+
+    /** Is the current instruction able to write to this destination register? */
+    bool canWrite(unsigned idx, DynInstPtr inst);
+
+    /** Size of Dependency of Map */
+    int depSize(unsigned idx);
+
+  protected:
+    // Eventually make this a map of lists for
+    // efficiency sake!
+    std::vector<std::list<DynInstPtr> > regMap;
+
+    InOrderCPU *cpu;
+};
+
+#endif
+
+
+
+
+
+
+
diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc
new file mode 100644 (file)
index 0000000..3106628
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * 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/resource.hh"
+#include "cpu/inorder/cpu.hh"
+using namespace std;
+
+Resource::Resource(string res_name, int res_id, int res_width,
+                   int res_latency, InOrderCPU *_cpu)
+    : resName(res_name), id(res_id),
+      width(res_width), latency(res_latency), cpu(_cpu)
+{
+    // Use to deny a instruction a resource.
+    deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0);
+}
+
+void
+Resource::init()
+{
+    // Set Up Resource Events to Appropriate Resource BandWidth
+    resourceEvent = new ResourceEvent[width];
+
+    initSlots();
+}
+
+void
+Resource::initSlots()
+{
+    // Add available slot numbers for resource
+    for (int slot_idx = 0; slot_idx < width; slot_idx++) {
+        availSlots.push_back(slot_idx);
+        resourceEvent[slot_idx].init(this, slot_idx);
+    }
+}
+
+std::string
+Resource::name()
+{
+    return cpu->name() + "."  + resName;
+}
+
+void
+Resource::regStats()
+{
+    instReqsProcessed
+        .name(name() + ".instReqsProcessed")
+        .desc("Number of Instructions Requests that completed in this resource.");
+}
+
+int
+Resource::slotsAvail()
+{
+    return availSlots.size();
+}
+
+int
+Resource::slotsInUse()
+{
+    return width - availSlots.size();
+}
+
+void
+Resource::freeSlot(int slot_idx)
+{
+    DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n",
+            reqMap[slot_idx]->inst->readTid(),
+            reqMap[slot_idx]->inst->seqNum,
+            slot_idx);
+
+    // Put slot number on this resource's free list
+    availSlots.push_back(slot_idx);
+
+    // Erase Request Pointer From Request Map
+    std::map<int, ResReqPtr>::iterator req_it = reqMap.find(slot_idx);
+
+    assert(req_it != reqMap.end());
+    reqMap.erase(req_it);
+
+}
+
+// TODO: More efficiently search for instruction's slot within
+// resource.
+int
+Resource::findSlot(DynInstPtr inst)
+{
+    map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+    map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+    int slot_num = -1;
+
+    while (map_it != map_end) {
+        if ((*map_it).second->getInst()->seqNum ==
+            inst->seqNum) {
+            slot_num = (*map_it).second->getSlot();
+        }
+        map_it++;
+    }
+
+    return slot_num;
+}
+
+int
+Resource::getSlot(DynInstPtr inst)
+{
+    int slot_num;
+
+    if (slotsAvail() != 0) {
+        slot_num = availSlots[0];
+
+        vector<int>::iterator vect_it = availSlots.begin();
+
+        assert(slot_num == *vect_it);
+
+        availSlots.erase(vect_it);
+    } else {
+        DPRINTF(Resource, "[tid:%i]: No slots in resource "
+                "available to service [sn:%i].\n", inst->readTid(),
+                inst->seqNum);
+        slot_num = -1;
+
+        map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+        map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+        while (map_it != map_end) {
+            if ((*map_it).second) {
+                DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n",
+                        (*map_it).second->getInst()->readTid(),
+                        (*map_it).second->getInst()->seqNum);
+            }
+            map_it++;
+        }
+    }
+
+    return slot_num;
+}
+
+ResReqPtr
+Resource::request(DynInstPtr inst)
+{
+    // See if the resource is already serving this instruction.
+    // If so, use that request;
+    bool try_request = false;
+    int slot_num;
+    int stage_num;
+    ResReqPtr inst_req = findRequest(inst);
+
+    if (inst_req) {
+        // If some preprocessing has to be done on instruction
+        // that has already requested once, then handle it here.
+        // update the 'try_request' variable if we should
+        // re-execute the request.
+        requestAgain(inst, try_request);
+
+        slot_num = inst_req->getSlot();
+        stage_num = inst_req->getStageNum();
+    } else {
+        // Get new slot # for instruction
+        slot_num = getSlot(inst);
+
+        if (slot_num != -1) {
+            // Get Stage # from Schedule Entry
+            stage_num = inst->resSched.top()->stageNum;
+            unsigned cmd = inst->resSched.top()->cmd;
+
+            // Generate Resource Request
+            inst_req = getRequest(inst, stage_num, id, slot_num, cmd);
+
+            if (inst->staticInst) {
+                DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n",
+                        inst->readTid(), inst->seqNum);
+            } else {
+                DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n",
+                        inst->readTid());
+            }
+
+            reqMap[slot_num] = inst_req;
+
+            try_request = true;
+        }
+    }
+
+    if (try_request) {
+        // Schedule execution of resource
+        scheduleExecution(slot_num);
+    } else {
+        inst_req = deniedReq;
+        rejectRequest(inst);
+    }
+
+    return inst_req;
+}
+
+void
+Resource::requestAgain(DynInstPtr inst, bool &do_request)
+{
+    do_request = true;
+
+    if (inst->staticInst) {
+        DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n",
+                inst->readTid(), inst->seqNum);
+    } else {
+        DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n",
+                inst->readTid());
+    }
+}
+
+ResReqPtr
+Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+                     int slot_num, unsigned cmd)
+{
+    return new ResourceRequest(this, inst, stage_num, id, slot_num,
+                               cmd);
+}
+
+ResReqPtr
+Resource::findRequest(DynInstPtr inst)
+{
+    map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+    map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+    while (map_it != map_end) {
+        if ((*map_it).second &&
+            (*map_it).second->getInst() == inst) {
+            return (*map_it).second;
+        }
+        map_it++;
+    }
+
+    return NULL;
+}
+
+void
+Resource::rejectRequest(DynInstPtr inst)
+{
+    DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n",
+            inst->readTid(), inst->seqNum);
+}
+
+void
+Resource::execute(int slot_idx)
+{
+    DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n",
+            reqMap[slot_idx]->getTid(), name());
+    reqMap[slot_idx]->setCompleted(true);
+    reqMap[slot_idx]->fault = NoFault;
+    reqMap[slot_idx]->done();
+}
+
+void
+Resource::deactivateThread(unsigned tid)
+{
+    // In the most basic case, deactivation means squashing everything
+    // from a particular thread
+    DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid);
+    squash(dummy_inst, 0, 0, tid);
+}
+
+void
+Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
+{
+    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);
+
+            int req_slot_num = req_ptr->getSlot();
+
+            unscheduleEvent(req_slot_num);
+
+            // 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]);
+    }
+}
+
+
+Tick
+Resource::ticks(int num_cycles)
+{
+    return cpu->ticks(num_cycles);
+}
+
+
+void
+Resource::scheduleExecution(int slot_num)
+{
+    int res_latency = getLatency(slot_num);
+
+    if (res_latency >= 1) {
+        scheduleEvent(slot_num, res_latency);
+    } else {
+        execute(slot_num);
+    }
+}
+
+void
+Resource::scheduleEvent(int slot_idx, int delay)
+{
+    DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n",
+            reqMap[slot_idx]->inst->readTid(),
+            reqMap[slot_idx]->inst->seqNum,
+            cpu->ticks(delay) + curTick);
+    resourceEvent[slot_idx].scheduleEvent(delay);
+}
+
+bool
+Resource::scheduleEvent(DynInstPtr inst, int delay)
+{
+    int slot_idx = findSlot(inst);
+
+    if(slot_idx != -1)
+        resourceEvent[slot_idx].scheduleEvent(delay);
+
+    return slot_idx;
+}
+
+void
+Resource::unscheduleEvent(int slot_idx)
+{
+    resourceEvent[slot_idx].unscheduleEvent();
+}
+
+bool
+Resource::unscheduleEvent(DynInstPtr inst)
+{
+    int slot_idx = findSlot(inst);
+
+    if(slot_idx != -1)
+        resourceEvent[slot_idx].unscheduleEvent();
+
+    return slot_idx;
+}
+
+int ResourceRequest::resReqID = 0;
+
+int ResourceRequest::resReqCount = 0;
+
+void
+ResourceRequest::done(bool completed)
+{
+    DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n",
+            res->name(), inst->seqNum, inst->readTid());
+
+    setCompleted(completed);
+
+    // Add to remove list
+    res->cpu->reqRemoveList.push(res->reqMap[slotNum]);
+
+    // Free Slot So Another Instruction Can Use This Resource
+    res->freeSlot(slotNum);
+
+    res->instReqsProcessed++;
+}
+
+ResourceEvent::ResourceEvent()
+    : Event((Event::Priority)Resource_Event_Pri)
+{ }
+
+ResourceEvent::ResourceEvent(Resource *res, int slot_idx)
+  : Event((Event::Priority)Resource_Event_Pri), resource(res),
+      slotIdx(slot_idx)
+{ }
+
+void
+ResourceEvent::init(Resource *res, int slot_idx)
+{
+    resource = res;
+    slotIdx = slot_idx;
+}
+
+void
+ResourceEvent::process()
+{
+    resource->execute(slotIdx);
+}
+
+const char *
+ResourceEvent::description()
+{
+    string desc = resource->name() + " event";
+
+    return desc.c_str();
+}
diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh
new file mode 100644 (file)
index 0000000..e353625
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * 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_HH__
+#define __CPU_INORDER_RESOURCE_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inst_seq.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class Event;
+class InOrderCPU;
+class ResourceEvent;
+class ResourceRequest;
+
+typedef ResourceRequest ResReq;
+typedef ResourceRequest* ResReqPtr;
+
+class Resource {
+  public:
+    typedef ThePipeline::DynInstPtr DynInstPtr;
+
+    friend class ResourceEvent;
+    friend class ResourceRequest;
+
+  public:
+    Resource(std::string res_name, int res_id, int res_width,
+             int res_latency, InOrderCPU *_cpu);
+    virtual ~Resource() {}
+
+    /** Return name of this resource */
+    virtual std::string name();
+
+    /** Define this function if resource, has a port to connect to an outside
+     *  simulation object.
+     */
+    virtual Port* getPort(const std::string &if_name, int idx) { return NULL; }
+
+    /** Return ID for this resource */
+    int getId() { return id; }
+
+    /** Any extra initiliazation stuff can be set up using this function that
+     * should get called before the simulation starts (tick 0)
+     */
+    virtual void init();    
+    virtual void initSlots();
+
+    /** Tasks to perform when simulation starts */
+    //virtual void startup() { }
+
+    /** Register Stats for this resource */
+    virtual void regStats();
+
+    /** Resources that care about thread activation override this. */
+    virtual void activateThread(unsigned tid) { }
+
+    /** Deactivate Thread. Default action is to squash all instructions
+     *  from deactivated thread.
+     */
+    virtual void deactivateThread(unsigned tid);
+
+    /** Resources that care when an instruction has been graduated
+     *  can override this
+     */
+    virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { }
+
+    /** Request usage of this resource. Returns a ResourceRequest object
+     *  with all the necessary resource information
+     */
+    virtual ResourceRequest* request(DynInstPtr inst);
+
+    /** Get the next available slot in this resource. Instruction is passed
+     *  so that resources can check the instruction before allocating a slot
+     *  if necessary.
+     */
+    virtual int getSlot(DynInstPtr inst);
+
+    /** Find the slot that this instruction is using in a resource */
+    virtual int findSlot(DynInstPtr inst);
+
+    /** Free a resource slot */
+    virtual void freeSlot(int slot_idx);
+
+    /** Request usage of a resource for this instruction. If this instruction already
+     *  has made this request to this resource, and that request is uncompleted
+     *  this function will just return that request
+     */
+    virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+                                        int res_idx, int slot_num,
+                                        unsigned cmd);
+
+    /** Schedule Execution of This Resource For A Given Slot*/
+    virtual void scheduleExecution(int slot_idx);
+
+    /** 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_idx);
+
+    /** Fetch on behalf of an instruction. Will check to see
+     *  if instruction is actually in resource before
+     *  trying to fetch. Needs to be defined for derived units.
+     */
+    virtual Fault doFetchAccess(DynInstPtr inst)
+    { panic("doFetchAccess undefined for %s", name()); return NoFault; }
+
+    /** Read/Write on behalf of an instruction. Will check to see
+     *  if instruction is actually in resource before
+     *  trying to do access.Needs to be defined for derived units.
+     */
+    virtual Fault doDataAccess(DynInstPtr inst)
+    { panic("doDataAccess undefined for %s", name()); return NoFault; }
+
+    /** Squash All Requests After This Seq Num */
+    virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+    /** The number of instructions available that this resource can
+     *  can still process
+     */
+    int slotsAvail();
+
+    /** The number of instructions using this resource */
+    int slotsInUse();
+
+    /** Schedule resource event, regardless of its current state. */
+    void scheduleEvent(int slot_idx, int delay);
+
+    /** Find instruction in list, Schedule resource event, regardless of its current state. */
+    bool scheduleEvent(DynInstPtr inst, int delay);
+
+    /** Unschedule resource event, regardless of its current state. */
+    void unscheduleEvent(int slot_idx);
+
+    /** Unschedule resource event, regardless of its current state. */
+    bool unscheduleEvent(DynInstPtr inst);
+
+    /** Return the number of cycles in 'Tick' format */
+    Tick ticks(int numCycles);
+
+    /** Find the request that corresponds to this instruction */
+    virtual ResReqPtr findRequest(DynInstPtr inst);
+
+    /** */
+    virtual void rejectRequest(DynInstPtr inst);
+
+    /** Request a Resource again. Some resources have to special process this
+     *  in subsequent accesses.
+     */
+    virtual void requestAgain(DynInstPtr inst, bool &try_request);
+
+    /** Return Latency of Resource */
+    /*  Can be overridden for complex cases */
+    virtual int getLatency(int slot_num) { return latency; }
+
+  protected:
+    /** The name of this resource */
+    std::string resName;
+
+    /** ID of the resource. The Resource Pool uses this # to identify this
+     *  resource.
+     */
+    int id;
+
+    /** The number of instructions the resource can simultaneously
+     *  process.
+     */
+    int width;
+
+    /** Constant latency for this resource.
+     *  Note: Dynamic latency resources set this to 0 and
+     *  manage the latency themselves
+     */
+    const int latency;
+
+  public:
+    /** Mapping of slot-numbers to the resource-request pointers */
+    std::map<int, ResReqPtr> reqMap;
+
+    /** A list of all the available execution slots for this resource.
+     *  This correlates with the actual resource event idx.
+     */
+    std::vector<int> availSlots;
+
+    /** The CPU(s) that this resource interacts with */
+    InOrderCPU *cpu;
+
+  protected:
+    /** The resource event used for scheduling resource slots on the
+     *  event queue
+     */
+    ResourceEvent *resourceEvent;
+
+    /** Default denied resource request pointer*/
+    ResReqPtr deniedReq;
+
+  public:
+    /////////////////////////////////////////////////////////////////
+    //
+    // DEFAULT RESOURCE STATISTICS
+    //
+    /////////////////////////////////////////////////////////////////
+    /** Number of Instruction Requests the Resource Processes */
+    Stats::Scalar<> instReqsProcessed;
+};
+
+class ResourceEvent : public Event
+{
+  public:
+    /** Pointer to the CPU. */
+    Resource *resource;
+
+
+    /// Resource events that come before other associated CPU events
+    /// (for InOrderCPU model).
+    /// check src/sim/eventq.hh for more event priorities.
+    enum InOrderPriority {
+        Resource_Event_Pri     =   45,
+    };
+
+    /** The Resource Slot that this event is servicing */
+    int slotIdx;
+
+    /** Constructs a resource event. */
+    ResourceEvent();
+    ResourceEvent(Resource *res, int slot_idx);
+    virtual ~ResourceEvent() { }
+
+    /** Initialize data for this resource event. */
+    virtual void init(Resource *res, int slot_idx);
+
+    /** Processes a resource event. */
+    virtual void process();
+
+    /** Returns the description of the resource event. */
+    const char *description();
+
+    /** Set slot idx for event */
+    void setSlot(int slot) { slotIdx = slot; }
+
+    /** Schedule resource event, regardless of its current state. */
+    void scheduleEvent(int delay)
+    {
+        if (squashed())
+          mainEventQueue.reschedule(this, curTick + resource->ticks(delay));
+        else if (!scheduled())
+          mainEventQueue.schedule(this, curTick + resource->ticks(delay));
+    }
+
+    /** Unschedule resource event, regardless of its current state. */
+    void unscheduleEvent()
+    {
+        if (scheduled())
+            squash();
+    }
+
+};
+
+class ResourceRequest
+{
+  public:
+    typedef ThePipeline::DynInstPtr DynInstPtr;
+
+    static int resReqID;
+
+    static int resReqCount;
+
+  public:
+    ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num,
+                    int res_idx, int slot_num, unsigned _cmd)
+        : res(_res), inst(_inst), cmd(_cmd),  stageNum(stage_num),
+          resIdx(res_idx), slotNum(slot_num), completed(false),
+          squashed(false), processing(false), waiting(false)
+    {
+        reqID = resReqID++;
+        resReqCount++;
+        DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount);
+
+        if (resReqCount > 100) {
+            fatal("Too many undeleted resource requests. Memory leak?\n");
+        }
+    }
+
+    virtual ~ResourceRequest()
+    {
+        resReqCount--;
+        DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount);
+    }
+
+    int reqID;
+
+    /** Acknowledge that this is a request is done and remove
+     *  from resource.
+     */
+    void done(bool completed = true);
+
+    /////////////////////////////////////////////
+    //
+    // GET RESOURCE REQUEST IDENTIFICATION / INFO
+    //
+    /////////////////////////////////////////////
+    /** Get Resource Index */
+    int getResIdx() { return resIdx; }
+
+    /** Get Slot Number */
+    int getSlot() { return slotNum; }
+
+    /** Get Stage Number */
+    int getStageNum() { return stageNum; }
+
+    /** Set/Get Thread Ids */
+    void setTid(unsigned _tid) { tid = _tid; }
+    int getTid() { return tid; }
+
+    /** Instruction this request is for */
+    DynInstPtr getInst() { return inst; }
+
+    /** Data from this request. Overridden by Resource-Specific Request
+     *  Objects
+     */
+    virtual PacketDataPtr getData() { return NULL; }
+
+    /** Pointer to Resource that is being used */
+    Resource *res;
+
+    /** Instruction being used */
+    DynInstPtr inst;
+
+    /** Fault Associated With This Resource Request */
+    Fault fault;
+
+    /** Command For This Resource */
+    unsigned cmd;
+
+    ////////////////////////////////////////
+    //
+    // GET RESOURCE REQUEST STATUS FROM VARIABLES
+    //
+    ////////////////////////////////////////
+    /** Get/Set Completed variables */
+    bool isCompleted() { return completed; }
+    void setCompleted(bool cond = true) { completed = cond; }
+
+    /** Get/Set Squashed variables */
+    bool isSquashed() { return squashed; }
+    void setSquashed() { squashed = true; }
+
+    /** Get/Set IsProcessing variables */
+    bool isProcessing() { return processing; }
+    void setProcessing() { processing = true; }
+
+    /** Get/Set IsWaiting variables */
+    bool isWaiting() { return waiting; }
+    void setWaiting() { waiting = true; }
+
+  protected:
+    /** Resource Identification */
+    int tid;
+    int stageNum;
+    int resIdx;
+    int slotNum;
+
+    /** Resource Status */
+    bool completed;
+    bool squashed;
+    bool processing;
+    bool waiting;
+};
+
+#endif //__CPU_INORDER_RESOURCE_HH__
diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc
new file mode 100644 (file)
index 0000000..4a0258e
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * 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/resource_pool.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+#include <vector>
+#include <list>
+
+using namespace std;
+using namespace ThePipeline;
+
+ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
+    : cpu(_cpu)
+{
+    //@todo: use this function to instantiate the resources in resource pool. This will help in the
+    //auto-generation of this pipeline model.
+    //ThePipeline::addResources(resources, memObjects);
+
+    // Declare Resource Objects
+    // name - id - bandwidth - latency - CPU - Parameters
+    // --------------------------------------------------
+    resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params));
+
+    resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params));
+
+    memObjects.push_back(ICache);
+    resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params));
+
+    for (int i = 0; i < params->numberOfThreads; i++) {
+        char fbuff_name[20];
+        sprintf(fbuff_name, "Fetch-Buffer-T%i", i);
+        resources.push_back(new InstBuffer(fbuff_name, FetchBuff + i, 4, 0, _cpu, params));
+    }
+
+    resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params));
+
+    resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params));
+
+    memObjects.push_back(DCache);
+    resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params));
+}
+
+void
+ResourcePool::init()
+{
+    for (int i=0; i < resources.size(); i++) {
+        resources[i]->init();
+    }
+}
+
+string
+ResourcePool::name()
+{
+    return cpu->name() + ".ResourcePool";
+}
+
+
+void
+ResourcePool::regStats()
+{
+    DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->regStats();
+    }
+}
+
+Port *
+ResourcePool::getPort(const std::string &if_name, int idx)
+{
+    for (int i = 0; i < memObjects.size(); i++) {
+        int obj_idx = memObjects[i];
+        Port *port = resources[obj_idx]->getPort(if_name, idx);
+        if (port != NULL) {
+            return port;
+        }
+    }
+
+    return NULL;
+}
+
+unsigned
+ResourcePool::getPortIdx(const std::string &port_name)
+{
+    for (int i = 0; i < memObjects.size(); i++) {
+        unsigned obj_idx = memObjects[i];
+        Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
+        if (port != NULL) {
+            return obj_idx;
+        }
+    }
+
+    return 0;
+}
+
+ResReqPtr
+ResourcePool::request(int res_idx, DynInstPtr inst)
+{
+    //Make Sure This is a valid resource ID
+    assert(res_idx >= 0 && res_idx < resources.size());
+
+    return resources[res_idx]->request(inst);
+}
+
+void
+ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid)
+{
+    resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid);
+}
+
+int
+ResourcePool::slotsAvail(int res_idx)
+{
+    return resources[res_idx]->slotsAvail();
+}
+
+int
+ResourcePool::slotsInUse(int res_idx)
+{
+    return resources[res_idx]->slotsInUse();
+}
+
+void
+ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
+                            int delay,  int res_idx, int tid)
+{
+    assert(delay >= 0);
+
+    ResPoolEvent *res_pool_event = new ResPoolEvent(this);
+
+    switch (e_type)
+    {
+      case InOrderCPU::ActivateThread:
+        {
+            DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->bdelaySeqNum,
+                                     inst->readTid());
+            res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+        }
+        break;
+
+      case InOrderCPU::SuspendThread:
+      case InOrderCPU::DeallocateThread:
+        {
+            DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->bdelaySeqNum,
+                                     tid);
+
+            res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+        }
+        break;
+
+      case ResourcePool::InstGraduated:
+        {
+            DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->seqNum,
+                                     inst->readTid());
+            res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+        }
+        break;
+
+      case ResourcePool::SquashAll:
+        {
+            DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->bdelaySeqNum,
+                                     inst->readTid());
+            res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+        }
+        break;
+
+      default:
+        DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type);
+        ; // If Resource Pool doesnt recognize event, we ignore it.
+    }
+}
+
+void
+ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
+{
+    resources[res_idx]->unscheduleEvent(inst);
+}
+
+void
+ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n",
+            stage_num, tid, done_seq_num);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->squash(inst, stage_num, done_seq_num, tid);
+    }
+}
+
+void
+ResourcePool::activateAll(unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n",
+            tid);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->activateThread(tid);
+    }
+}
+
+void
+ResourcePool::deactivateAll(unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n",
+            tid);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->deactivateThread(tid);
+    }
+}
+
+void
+ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n",
+            tid, seq_num);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->instGraduated(seq_num, tid);
+    }
+}
+
+ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
+    : Event(&mainEventQueue, CPU_Tick_Pri),
+      resPool(_resPool)
+{ eventType = (InOrderCPU::CPUEventType) Default; }
+
+void
+ResourcePool::ResPoolEvent::process()
+{
+    switch (eventType)
+    {
+      case InOrderCPU::ActivateThread:
+        resPool->activateAll(tid);
+        break;
+
+      case InOrderCPU::SuspendThread:
+      case InOrderCPU::DeallocateThread:
+        resPool->deactivateAll(tid);
+        break;
+
+      case ResourcePool::InstGraduated:
+        resPool->instGraduated(seqNum, tid);
+        break;
+
+      case ResourcePool::SquashAll:
+        resPool->squashAll(inst, stageNum, seqNum, tid);
+        break;
+
+      default:
+        fatal("Unrecognized Event Type");
+    }
+
+    resPool->cpu->cpuEventRemoveList.push(this);
+}
+
+
+const char *
+ResourcePool::ResPoolEvent::description()
+{
+    return "Resource Pool event";
+}
+
+/** Schedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::scheduleEvent(int delay)
+{
+    if (squashed())
+        reschedule(curTick + resPool->cpu->cycles(delay));
+    else if (!scheduled())
+        schedule(curTick + resPool->cpu->cycles(delay));
+}
+
+/** Unschedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::unscheduleEvent()
+{
+    if (scheduled())
+        squash();
+}
diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc
new file mode 100644 (file)
index 0000000..94af68c
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * 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/resource_pool.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+#include <vector>
+#include <list>
+
+using namespace std;
+using namespace ThePipeline;
+
+ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
+    : cpu(_cpu)
+{
+    //@todo: use this function to instantiate the resources in resource pool. This will help in the
+    //auto-generation of this pipeline model.
+    //ThePipeline::addResources(resources, memObjects);
+
+    // Declare Resource Objects
+    // name - id - bandwidth - latency - CPU - Parameters
+    // --------------------------------------------------
+    resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params));
+
+    resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params));
+
+    memObjects.push_back(ICache);
+    resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params));
+
+    resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params));
+
+    resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params));
+
+    resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params));
+
+    memObjects.push_back(DCache);
+    resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params));
+
+    resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params));
+}
+
+void
+ResourcePool::init()
+{
+    for (int i=0; i < resources.size(); i++) {
+        DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name());
+        
+        resources[i]->init();
+    }
+}
+
+string
+ResourcePool::name()
+{
+    return cpu->name() + ".ResourcePool";
+}
+
+
+void
+ResourcePool::regStats()
+{
+    DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->regStats();
+    }
+}
+
+Port *
+ResourcePool::getPort(const std::string &if_name, int idx)
+{
+    DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name);
+
+    for (int i = 0; i < memObjects.size(); i++) {
+        int obj_idx = memObjects[i];
+        Port *port = resources[obj_idx]->getPort(if_name, idx);
+        if (port != NULL) {
+            DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name,
+                    resources[obj_idx]->name(), obj_idx);
+            return port;
+        }
+    }
+
+    return NULL;
+}
+
+unsigned
+ResourcePool::getPortIdx(const std::string &port_name)
+{
+    DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name);
+
+    for (int i = 0; i < memObjects.size(); i++) {
+        unsigned obj_idx = memObjects[i];
+        Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
+        if (port != NULL) {
+            DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name);
+            return obj_idx;
+        }
+    }
+
+    return 0;
+}
+
+ResReqPtr
+ResourcePool::request(int res_idx, DynInstPtr inst)
+{
+    //Make Sure This is a valid resource ID
+    assert(res_idx >= 0 && res_idx < resources.size());
+
+    return resources[res_idx]->request(inst);
+}
+
+void
+ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid)
+{
+    resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid);
+}
+
+int
+ResourcePool::slotsAvail(int res_idx)
+{
+    return resources[res_idx]->slotsAvail();
+}
+
+int
+ResourcePool::slotsInUse(int res_idx)
+{
+    return resources[res_idx]->slotsInUse();
+}
+
+void
+ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
+                            int delay,  int res_idx, int tid)
+{
+    assert(delay >= 0);
+
+    ResPoolEvent *res_pool_event = new ResPoolEvent(this);
+
+    switch (e_type)
+    {
+      case InOrderCPU::ActivateThread:
+        {
+            DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->bdelaySeqNum,
+                                     inst->readTid());
+            mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+        }
+        break;
+
+      case InOrderCPU::SuspendThread:
+      case InOrderCPU::DeallocateThread:
+        {
+            DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->bdelaySeqNum,
+                                     tid);
+
+            mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+        }
+        break;
+
+      case ResourcePool::InstGraduated:
+        {
+            DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->seqNum,
+                                     inst->readTid());
+            mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+        }
+        break;
+
+      case ResourcePool::SquashAll:
+        {
+            DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n",
+                    curTick + delay);
+            res_pool_event->setEvent(e_type,
+                                     inst,
+                                     inst->squashingStage,
+                                     inst->bdelaySeqNum,
+                                     inst->readTid());
+            mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+        }
+        break;
+
+      default:
+        DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type);
+        ; // If Resource Pool doesnt recognize event, we ignore it.
+    }
+}
+
+void
+ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
+{
+    resources[res_idx]->unscheduleEvent(inst);
+}
+
+void
+ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n",
+            stage_num, tid, done_seq_num);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->squash(inst, stage_num, done_seq_num, tid);
+    }
+}
+
+void
+ResourcePool::activateAll(unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n",
+            tid);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->activateThread(tid);
+    }
+}
+
+void
+ResourcePool::deactivateAll(unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n",
+            tid);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->deactivateThread(tid);
+    }
+}
+
+void
+ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid)
+{
+    DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n",
+            tid, seq_num);
+
+    int num_resources = resources.size();
+
+    for (int idx = 0; idx < num_resources; idx++) {
+        resources[idx]->instGraduated(seq_num, tid);
+    }
+}
+
+ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
+    : Event(CPU_Tick_Pri),
+      resPool(_resPool)
+{ eventType = (InOrderCPU::CPUEventType) Default; }
+
+void
+ResourcePool::ResPoolEvent::process()
+{
+    switch (eventType)
+    {
+      case InOrderCPU::ActivateThread:
+        resPool->activateAll(tid);
+        break;
+
+      case InOrderCPU::SuspendThread:
+      case InOrderCPU::DeallocateThread:
+        resPool->deactivateAll(tid);
+        break;
+
+      case ResourcePool::InstGraduated:
+        resPool->instGraduated(seqNum, tid);
+        break;
+
+      case ResourcePool::SquashAll:
+        resPool->squashAll(inst, stageNum, seqNum, tid);
+        break;
+
+      default:
+        fatal("Unrecognized Event Type");
+    }
+
+    resPool->cpu->cpuEventRemoveList.push(this);
+}
+
+
+const char *
+ResourcePool::ResPoolEvent::description()
+{
+    return "Resource Pool event";
+}
+
+/** Schedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::scheduleEvent(int delay)
+{
+    if (squashed())
+      mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay));
+    else if (!scheduled())
+      mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay));
+}
+
+/** Unschedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::unscheduleEvent()
+{
+    if (scheduled())
+        squash();
+}
diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh
new file mode 100644 (file)
index 0000000..35fce7d
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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_POOL_HH__
+#define __CPU_INORDER_RESOURCE_POOL_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inst_seq.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/params.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/cpu.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class Event;
+class InOrderCPU;
+class Resource;
+class ResourceEvent;
+
+class ResourcePool {
+  public:
+    typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+  public:
+    // List of Resource Pool Events that extends
+    // the list started by the CPU
+    // NOTE(1): Resource Pool also uses event list
+    // CPUEventType defined in inorder/cpu.hh
+    enum ResPoolEventType {
+        InstGraduated = InOrderCPU::NumCPUEvents,
+        SquashAll,
+        Default
+    };
+
+    class ResPoolEvent : public Event
+    {
+      protected:
+        /** Resource Pool */
+        ResourcePool *resPool;
+
+      public:
+        InOrderCPU::CPUEventType eventType;
+
+        DynInstPtr inst;
+
+        InstSeqNum seqNum;
+
+        int stageNum;
+
+        unsigned tid;
+
+      public:
+        /** Constructs a resource event. */
+        ResPoolEvent(ResourcePool *_resPool);
+
+        /** Set Type of Event To Be Scheduled */
+        void setEvent(InOrderCPU::CPUEventType e_type,
+                      DynInstPtr _inst,
+                      int stage_num,
+                      InstSeqNum seq_num,
+                      unsigned _tid)
+        {
+            eventType = e_type;
+            inst = _inst;
+            seqNum = seq_num;
+            stageNum = stage_num;
+            tid = _tid;
+        }
+
+        /** Processes a resource event. */
+        virtual void process();
+
+        /** Returns the description of the resource event. */
+        const char *description();
+
+        /** Schedule Event */
+        void scheduleEvent(int delay);
+
+        /** Unschedule This Event */
+        void unscheduleEvent();
+    };
+
+  public:
+  ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params);
+    virtual ~ResourcePool() {}
+
+    std::string name();
+
+    std::string name(int res_idx) { return resources[res_idx]->name(); }
+
+    void init();
+
+    /** Register Statistics in All Resources */
+    void regStats();
+
+    /** Returns a specific port. */
+    Port* getPort(const std::string &if_name, int idx);
+
+    /** Returns a specific port. */
+    unsigned getPortIdx(const std::string &if_name);
+
+    Resource* getResource(int res_idx) { return resources[res_idx]; }
+
+    /** Request usage of this resource. Returns -1 if not granted and
+     *  a positive request tag if granted.
+     */
+    ResReqPtr request(int res_idx, DynInstPtr inst);
+
+    /** Squash The Resource */
+    void squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid);
+
+    /** Squash All Resources in Pool after Done Seq. Num */
+    void squashAll(DynInstPtr inst, int stage_num,
+                   InstSeqNum done_seq_num, unsigned tid);
+
+    /** Activate Thread in all resources */
+    void activateAll(unsigned tid);
+
+    /** De-Activate Thread in all resources */
+    void deactivateAll(unsigned tid);
+
+    /** Broadcast graduation to all resources */
+    void instGraduated(InstSeqNum seq_num,unsigned tid);
+
+    /** The number of instructions available that a resource can
+     *  can still process.
+     */
+    int slotsAvail(int res_idx);
+
+    /** The number of instructions using a resource */
+    int slotsInUse(int res_idx);
+
+    /** Schedule resource event, regardless of its current state. */
+    void scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst = NULL,
+                       int delay = 0, int res_idx = 0, int tid = 0);
+
+   /** UnSchedule resource event, regardless of its current state. */
+    void unscheduleEvent(int res_idx, DynInstPtr inst);
+
+    /** Tasks to perform when simulation starts */
+    virtual void startup() { }
+
+    /** The CPU(s) that this resource interacts with */
+    InOrderCPU *cpu;
+
+    DynInstPtr dummyInst[ThePipeline::MaxThreads];
+
+  private:
+    std::vector<Resource *> resources;
+
+    std::vector<int> memObjects;
+
+};
+
+#endif //__CPU_INORDER_RESOURCE_HH__
diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc
new file mode 100644 (file)
index 0000000..8e3d256
--- /dev/null
@@ -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 (file)
index 0000000..2010c9f
--- /dev/null
@@ -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 (file)
index 0000000..66d0779
--- /dev/null
@@ -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 (file)
index 0000000..b945922
--- /dev/null
@@ -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 (file)
index 0000000..b563a30
--- /dev/null
@@ -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 (file)
index 0000000..66eb1af
--- /dev/null
@@ -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 (file)
index 0000000..79ca7a0
--- /dev/null
@@ -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 (file)
index 0000000..9d048d7
--- /dev/null
@@ -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 (file)
index 0000000..1628c32
--- /dev/null
@@ -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 (file)
index 0000000..3813de6
--- /dev/null
@@ -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 (file)
index 0000000..e412911
--- /dev/null
@@ -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 (file)
index 0000000..e969497
--- /dev/null
@@ -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 (file)
index 0000000..00f76f7
--- /dev/null
@@ -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 (file)
index 0000000..2b074bb
--- /dev/null
@@ -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 (file)
index 0000000..f4bbf3f
--- /dev/null
@@ -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 (file)
index 0000000..ad222b1
--- /dev/null
@@ -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 (file)
index 0000000..97924d2
--- /dev/null
@@ -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 (file)
index 0000000..f4851e8
--- /dev/null
@@ -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 (file)
index 0000000..7e2c988
--- /dev/null
@@ -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 (file)
index 0000000..e374fa1
--- /dev/null
@@ -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 (file)
index 0000000..0bd850c
--- /dev/null
@@ -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 (file)
index 0000000..abef112
--- /dev/null
@@ -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 (file)
index 0000000..762442c
--- /dev/null
@@ -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 (file)
index 0000000..cbe2ad8
--- /dev/null
@@ -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 (file)
index 0000000..9b0dece
--- /dev/null
@@ -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 (file)
index 0000000..c7fee60
--- /dev/null
@@ -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 (file)
index 0000000..ed697c4
--- /dev/null
@@ -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 (file)
index 0000000..2385911
--- /dev/null
@@ -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__
diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc
new file mode 100644 (file)
index 0000000..5e2c789
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * 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 "arch/isa_traits.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/inorder/thread_context.hh"
+
+using namespace TheISA;
+
+void
+InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
+{
+    // some things should already be set up
+    assert(getProcessPtr() == old_context->getProcessPtr());
+
+    // copy over functional state
+    setStatus(old_context->status());
+    copyArchRegs(old_context);
+    //setCpuId(0/*old_context->readCpuId()*/);
+
+    thread->funcExeInst = old_context->readFuncExeInst();
+    old_context->setStatus(ThreadContext::Unallocated);
+    thread->inSyscall = false;
+    thread->trapPending = false;
+}
+
+void
+InOrderThreadContext::activate(int delay)
+{
+    DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n",
+            getThreadNum());
+
+    if (thread->status() == ThreadContext::Active)
+        return;
+
+    // @TODO: Make this process useful again...
+    //if (thread->status() == ThreadContext::Unallocated) {
+        // Allows the CPU to drain partitioned resources
+        // before inserting thread into the CPU
+        // (e.g. bind physical registers)
+        //cpu->activateWhenReady(thread->readTid());
+        //return;
+    //}
+
+    thread->setStatus(ThreadContext::Active);
+
+    // status() == Suspended
+    cpu->activateContext(thread->readTid(), delay);
+}
+
+
+void
+InOrderThreadContext::suspend(int delay)
+{
+    DPRINTF(InOrderCPU, "Calling suspend on Thread Context %d\n",
+            getThreadNum());
+
+    if (thread->status() == ThreadContext::Suspended)
+        return;
+
+    thread->setStatus(ThreadContext::Suspended);
+    cpu->suspendContext(thread->readTid(), delay);
+}
+
+void
+InOrderThreadContext::deallocate(int delay)
+{
+    DPRINTF(InOrderCPU, "Calling deallocate on Thread Context %d\n",
+            getThreadNum());
+
+    if (thread->status() == ThreadContext::Unallocated)
+        return;
+
+    thread->setStatus(ThreadContext::Unallocated);
+    cpu->deallocateContext(thread->readTid(), delay);
+}
+
+void
+InOrderThreadContext::halt(int delay)
+{
+    DPRINTF(InOrderCPU, "Calling halt on Thread Context %d\n",
+            getThreadNum());
+
+    if (thread->status() == ThreadContext::Halted)
+        return;
+
+    thread->setStatus(ThreadContext::Halted);
+    cpu->haltContext(thread->readTid(), delay);
+}
+
+
+void
+InOrderThreadContext::regStats(const std::string &name)
+{
+#if FULL_SYSTEM
+    thread->kernelStats = new Kernel::Statistics(cpu->system);
+    thread->kernelStats->regStats(name + ".kern");
+#endif
+    ;
+}
+
+
+void
+InOrderThreadContext::serialize(std::ostream &os)
+{
+#if FULL_SYSTEM
+    if (thread->kernelStats)
+        thread->kernelStats->serialize(os);
+#endif
+    ;
+}
+
+
+void
+InOrderThreadContext::unserialize(Checkpoint *cp, const std::string &section)
+{
+#if FULL_SYSTEM
+    if (thread->kernelStats)
+        thread->kernelStats->unserialize(cp, section);
+#endif
+    ;
+}
+
+TheISA::MachInst
+InOrderThreadContext:: getInst()
+{
+    return thread->getInst();
+}
+
+
+void
+InOrderThreadContext::copyArchRegs(ThreadContext *tc)
+{
+    unsigned tid = thread->readTid();
+    PhysRegIndex renamed_reg;
+
+    // First loop through the integer registers.
+    for (int i = 0; i < TheISA::NumIntRegs; ++i) {
+        renamed_reg = cpu->renameMap[tid].lookup(i);
+
+        DPRINTF(InOrderCPU, "Copying over register %i, had data %lli, "
+                "now has data %lli.\n",
+                renamed_reg, cpu->readIntReg(renamed_reg, tid),
+                tc->readIntReg(i));
+
+        cpu->setIntReg(renamed_reg, tc->readIntReg(i), tid);
+    }
+
+    // Then loop through the floating point registers.
+    for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
+        renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag);
+        cpu->setFloatRegBits(renamed_reg, tc->readFloatRegBits(i), tid);
+    }
+
+    // Copy the misc regs.
+    TheISA::copyMiscRegs(tc, this);
+
+    // Then finally set the PC and the next PC.
+    cpu->setPC(tc->readPC(), tid);
+    cpu->setNextPC(tc->readNextPC(), tid);
+    cpu->setNextNPC(tc->readNextNPC(), tid);
+    this->thread->funcExeInst = tc->readFuncExeInst();
+}
+
+
+void
+InOrderThreadContext::clearArchRegs()
+{}
+
+
+uint64_t
+InOrderThreadContext::readIntReg(int reg_idx)
+{
+    return cpu->readIntReg(reg_idx, thread->readTid());
+}
+
+FloatReg
+InOrderThreadContext::readFloatReg(int reg_idx, int width)
+{
+    return cpu->readFloatReg(reg_idx, thread->readTid(), width);
+}
+
+FloatReg
+InOrderThreadContext::readFloatReg(int reg_idx)
+{
+    return cpu->readFloatReg(reg_idx, thread->readTid());
+}
+
+FloatRegBits
+InOrderThreadContext::readFloatRegBits(int reg_idx, int width)
+{
+    return cpu->readFloatRegBits(reg_idx, thread->readTid(), width);
+}
+
+FloatRegBits
+InOrderThreadContext::readFloatRegBits(int reg_idx)
+{
+    return cpu->readFloatRegBits(reg_idx, thread->readTid());
+}
+
+uint64_t
+InOrderThreadContext::readRegOtherThread(int reg_idx, unsigned tid)
+{
+    return cpu->readRegOtherThread(reg_idx, tid);
+}
+
+void
+InOrderThreadContext::setIntReg(int reg_idx, uint64_t val)
+{
+    cpu->setIntReg(reg_idx, val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //  cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+    cpu->setFloatReg(reg_idx, val, thread->readTid(), width);
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val)
+{
+    cpu->setFloatReg(reg_idx, val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val,
+                                    int width)
+{
+    cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width);
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+    cpu->setFloatRegBits(reg_idx, val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid)
+{
+    cpu->setRegOtherThread(misc_reg, val, tid);
+}
+
+void
+InOrderThreadContext::setPC(uint64_t val)
+{
+    DPRINTF(InOrderCPU, "Setting PC to %08p\n", val);
+    cpu->setPC(val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setNextPC(uint64_t val)
+{
+    DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val);
+    cpu->setNextPC(val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setNextNPC(uint64_t val)
+{
+    DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val);
+    cpu->setNextNPC(val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+{
+    cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+void
+InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val)
+{
+    cpu->setMiscReg(misc_reg, val, thread->readTid());
+
+    // Squash if we're not already in a state update mode.
+    //if (!thread->trapPending && !thread->inSyscall) {
+    //cpu->squashFromTC(thread->readTid());
+    //}
+}
+
+TheISA::IntReg
+InOrderThreadContext::getSyscallArg(int i)
+{
+    return cpu->getSyscallArg(i, thread->readTid());
+}
+
+void
+InOrderThreadContext::setSyscallArg(int i, IntReg val)
+{
+    cpu->setSyscallArg(i, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setSyscallReturn(SyscallReturn return_value)
+{
+    cpu->setSyscallReturn(return_value, thread->readTid());
+}
diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh
new file mode 100644 (file)
index 0000000..919d5d2
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * 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_THREAD_CONTEXT_HH__
+#define __CPU_INORDER_THREAD_CONTEXT_HH__
+
+#include "cpu/exetrace.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/cpu.hh"
+
+class TranslatingPort;
+
+/**
+ * Derived ThreadContext class for use with the InOrderCPU.  It
+ * provides the interface for any external objects to access a
+ * single thread's state and some general CPU state.  Any time
+ * external objects try to update state through this interface,
+ * the CPU will create an event to squash all in-flight
+ * instructions in order to ensure state is maintained correctly.
+ * It must be defined specifically for the InOrderCPU because
+ * not all architectural state is located within the O3ThreadState
+ * (such as the commit PC, and registers), and specific actions
+ * must be taken when using this interface (such as squashing all
+ * in-flight instructions when doing a write to this interface).
+ */
+class InOrderThreadContext : public ThreadContext
+{
+  public:
+    InOrderThreadContext() { }
+
+   /** Pointer to the CPU. */
+    InOrderCPU *cpu;
+
+    /** Pointer to the thread state that this TC corrseponds to. */
+    InOrderThreadState *thread;
+
+
+    /** Returns a pointer to the ITB. */
+    TheISA::ITB *getITBPtr() { return cpu->itb; }
+
+    /** Returns a pointer to the DTB. */
+    TheISA::DTB *getDTBPtr() { return cpu->dtb; }
+
+    System *getSystemPtr() { return cpu->system; }
+
+    /** Returns a pointer to this CPU. */
+    virtual BaseCPU *getCpuPtr() { return cpu; }
+
+    /** Returns a pointer to this CPU. */
+    virtual std::string getCpuName() { return cpu->name(); }
+
+    /** Reads this CPU's ID. */
+    virtual int cpuId() { return cpu->cpuId(); }
+
+    virtual int contextId() { return thread->contextId(); }
+
+    virtual void setContextId(int id) { thread->setContextId(id); }
+
+    /** Returns this thread's ID number. */
+    virtual int threadId() { return thread->threadId(); }
+    virtual void setThreadId(int id) { return thread->setThreadId(id); }
+
+    virtual uint64_t readMicroPC()
+    { return 0; }
+
+    virtual void setMicroPC(uint64_t val) { };
+
+    virtual uint64_t readNextMicroPC()
+    { return 0; }
+
+    virtual void setNextMicroPC(uint64_t val) { };
+
+    virtual TranslatingPort *getMemPort() { return thread->getMemPort(); }
+
+    /** Returns a pointer to this thread's process. */
+    virtual Process *getProcessPtr() { return thread->getProcessPtr(); }
+
+    /** Returns this thread's status. */
+    virtual Status status() const { return thread->status(); }
+
+    /** Sets this thread's status. */
+    virtual void setStatus(Status new_status)
+    { thread->setStatus(new_status); }
+
+    /** Returns a pointer to the last graduated/committed instruction in the thread */
+    //DynInstPtr getLastGradInst() { return thread->getLastGradInst(); }
+
+    /** Set the status to Active.  Optional delay indicates number of
+     * cycles to wait before beginning execution. */
+    virtual void activate(int delay = 1);
+
+    /** Set the status to Suspended. */
+    virtual void suspend(int delay = 0);
+
+    /** Set the status to Unallocated. */
+    virtual void deallocate(int delay = 1);
+
+    /** Set the status to Halted. */
+    virtual void halt(int delay = 0);
+
+    /** Takes over execution of a thread from another CPU. */
+    virtual void takeOverFrom(ThreadContext *old_context);
+
+    /** Registers statistics associated with this TC. */
+    virtual void regStats(const std::string &name);
+
+    /** Serializes state. */
+    virtual void serialize(std::ostream &os);
+    /** Unserializes state. */
+    virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+    /** Returns this thread's ID number. */
+    virtual int getThreadNum() { return thread->readTid(); }
+
+    /** Returns the instruction this thread is currently committing.
+     *  Only used when an instruction faults.
+     */
+    virtual TheISA::MachInst getInst();
+
+    /** Copies the architectural registers from another TC into this TC. */
+    virtual void copyArchRegs(ThreadContext *tc);
+
+    /** Resets all architectural registers to 0. */
+    virtual void clearArchRegs();
+
+    /** Reads an integer register. */
+    virtual uint64_t readIntReg(int reg_idx);
+
+    virtual FloatReg readFloatReg(int reg_idx, int width);
+
+    virtual FloatReg readFloatReg(int reg_idx);
+
+    virtual FloatRegBits readFloatRegBits(int reg_idx, int width);
+
+    virtual FloatRegBits readFloatRegBits(int reg_idx);
+
+    virtual uint64_t readRegOtherThread(int misc_reg, unsigned tid);
+
+    /** Sets an integer register to a value. */
+    virtual void setIntReg(int reg_idx, uint64_t val);
+
+    virtual void setFloatReg(int reg_idx, FloatReg val, int width);
+
+    virtual void setFloatReg(int reg_idx, FloatReg val);
+
+    virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width);
+
+    virtual void setFloatRegBits(int reg_idx, FloatRegBits val);
+
+    virtual void setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid);
+
+    /** Reads this thread's PC. */
+    virtual uint64_t readPC()
+    { return cpu->readPC(thread->readTid()); }
+
+    /** Sets this thread's PC. */
+    virtual void setPC(uint64_t val);
+
+    /** Reads this thread's next PC. */
+    virtual uint64_t readNextPC()
+    { return cpu->readNextPC(thread->readTid()); }
+
+    /** Sets this thread's next PC. */
+    virtual void setNextPC(uint64_t val);
+
+    virtual uint64_t readNextNPC()
+    { return cpu->readNextNPC(thread->readTid()); }
+
+    virtual void setNextNPC(uint64_t val);
+
+    /** Reads a miscellaneous register. */
+    virtual MiscReg readMiscRegNoEffect(int misc_reg)
+    { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); }
+
+    /** Reads a misc. register, including any side-effects the
+     * read might have as defined by the architecture. */
+    virtual MiscReg readMiscReg(int misc_reg)
+    { return cpu->readMiscReg(misc_reg, thread->readTid()); }
+
+    /** Sets a misc. register. */
+    virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
+
+    /** Sets a misc. register, including any side-effects the
+     * write might have as defined by the architecture. */
+    virtual void setMiscReg(int misc_reg, const MiscReg &val);
+
+    virtual void activateContext(int delay)
+    { cpu->activateContext(thread->readTid(), delay); }
+
+    virtual void deallocateContext()
+    { cpu->deallocateContext(thread->readTid()); }
+
+    /** Returns the number of consecutive store conditional failures. */
+    // @todo: Figure out where these store cond failures should go.
+    virtual unsigned readStCondFailures()
+    { return thread->storeCondFailures; }
+
+    /** Sets the number of consecutive store conditional failures. */
+    virtual void setStCondFailures(unsigned sc_failures)
+    { thread->storeCondFailures = sc_failures; }
+
+    // Only really makes sense for old CPU model.  Lots of code
+    // outside the CPU still checks this function, so it will
+    // always return false to keep everything working.
+    /** Checks if the thread is misspeculating.  Because it is
+     * very difficult to determine if the thread is
+     * misspeculating, this is set as false. */
+    virtual bool misspeculating() { return false; }
+
+    /** Gets a syscall argument by index. */
+    virtual IntReg getSyscallArg(int i);
+
+    /** Sets a syscall argument. */
+    virtual void setSyscallArg(int i, IntReg val);
+
+    /** Sets the syscall return value. */
+    virtual void setSyscallReturn(SyscallReturn return_value);
+
+    /** Executes a syscall in SE mode. */
+    virtual void syscall(int64_t callnum)
+    { return cpu->syscall(callnum, thread->readTid()); }
+
+    /** Reads the funcExeInst counter. */
+    virtual Counter readFuncExeInst() { return thread->funcExeInst; }
+
+    virtual void changeRegFileContext(unsigned param,
+                                      unsigned val)
+    { panic("Not supported!"); }
+
+    /** This function exits the thread context in the CPU and returns
+     * 1 if the CPU has no more active threads (meaning it's OK to exit);
+     * Used in syscall-emulation mode when a thread executes the 'exit'
+     * syscall.
+     */
+    virtual int exit()
+    {
+        this->deallocate();
+
+        // If there are still threads executing in the system (for now
+        // this single cpu)
+        if (this->cpu->numActiveThreads() - 1 > 0)
+            return 0; // don't exit simulation
+        else
+            return 1; // exit simulation
+    }
+
+    virtual void setThreadRescheduleCondition(uint64_t cond)
+    {
+        this->deallocate();
+
+        this->setStatus(ThreadContext::Suspended);
+
+        activateContext(cond);
+    }
+};
+
+#endif
diff --git a/src/cpu/inorder/thread_state.hh b/src/cpu/inorder/thread_state.hh
new file mode 100644 (file)
index 0000000..eb4fe40
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2006 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
+ */
+
+#ifndef __CPU_INORDER_THREAD_STATE_HH__
+#define __CPU_INORDER_THREAD_STATE_HH__
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/thread_state.hh"
+
+class Event;
+class FunctionalMemory;
+class Process;
+class InOrderCPU;
+
+/**
+ * Class that has various thread state, such as the status, the
+ * current instruction being processed, whether or not the thread has
+ * a trap pending or is being externally updated, the ThreadContext
+ * pointer, etc.  It also handles anything related to a specific
+ * thread's process, such as syscalls and checking valid addresses.
+ */
+class InOrderThreadState : public ThreadState {
+    typedef ThreadContext::Status Status;
+
+  private:
+    /** Pointer to the CPU. */
+    InOrderCPU *cpu;
+
+  public:
+    /** Whether or not the thread is currently in syscall mode, and
+     * thus able to be externally updated without squashing.
+     */
+    bool inSyscall;
+
+    /** Whether or not the thread is currently waiting on a trap, and
+     * thus able to be externally updated without squashing.
+     */
+    bool trapPending;
+
+
+    InOrderThreadState(InOrderCPU *_cpu, int _thread_num, Process *_process, int _asid)
+        : ThreadState(reinterpret_cast<BaseCPU*>(_cpu), 0/*_thread_num*/, _process, 0/*_asid*/),
+          cpu(_cpu), inSyscall(0), trapPending(0)
+    { }
+
+    /** Handles the syscall. */
+    void syscall(int64_t callnum) { process->syscall(callnum, tc); }
+
+    /** Pointer to the ThreadContext of this thread. */
+    ThreadContext *tc;
+
+    /** Returns a pointer to the TC of this thread. */
+    ThreadContext *getTC() { return tc; }
+
+  int readTid() { return 0; }
+
+    /** Pointer to the last graduated instruction in the thread */
+    //DynInstPtr lastGradInst;
+};
+
+#endif // __CPU_INORDER_THREAD_STATE_HH__