summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2009-04-06 10:19:36 -0700
committerGabe Black <gblack@eecs.umich.edu>2009-04-06 10:19:36 -0700
commitd080581db1f9ee4e1e6d07d2b01c13c67908a391 (patch)
treecc484b289fa5a30c4631f9faa1d8b456bffeebfc /src/cpu
parent7a7c4c5fca83a8d47c7e71c9c080a882ebe204a9 (diff)
parent639cb0a42d953ee32bc7e96b0cdfa96cd40e9fc1 (diff)
downloadgem5-d080581db1f9ee4e1e6d07d2b01c13c67908a391.tar.xz
Merge ARM into the head. ARM will compile but may not actually work.
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/BaseCPU.py53
-rw-r--r--src/cpu/CheckerCPU.py42
-rw-r--r--src/cpu/ExeTracer.py3
-rw-r--r--src/cpu/IntelTrace.py3
-rw-r--r--src/cpu/LegionTrace.py3
-rw-r--r--src/cpu/NativeTrace.py3
-rw-r--r--src/cpu/SConscript15
-rw-r--r--src/cpu/activity.cc13
-rw-r--r--src/cpu/activity.hh10
-rw-r--r--src/cpu/base.cc212
-rw-r--r--src/cpu/base.hh100
-rw-r--r--src/cpu/base_dyn_inst.hh98
-rw-r--r--src/cpu/base_dyn_inst_impl.hh24
-rw-r--r--src/cpu/checker/cpu.cc55
-rw-r--r--src/cpu/checker/cpu.hh23
-rw-r--r--src/cpu/checker/cpu_impl.hh9
-rw-r--r--src/cpu/checker/thread_context.hh29
-rw-r--r--src/cpu/cpu_models.py3
-rw-r--r--src/cpu/cpuevent.hh9
-rw-r--r--src/cpu/exetrace.cc82
-rw-r--r--src/cpu/exetrace.hh14
-rw-r--r--src/cpu/inorder/InOrderCPU.py79
-rw-r--r--src/cpu/inorder/InOrderTrace.py35
-rw-r--r--src/cpu/inorder/SConscript90
-rw-r--r--src/cpu/inorder/SConsopts33
-rw-r--r--src/cpu/inorder/comm.hh112
-rw-r--r--src/cpu/inorder/cpu.cc1253
-rw-r--r--src/cpu/inorder/cpu.hh680
-rw-r--r--src/cpu/inorder/first_stage.cc248
-rw-r--r--src/cpu/inorder/first_stage.hh97
-rw-r--r--[-rwxr-xr-x]src/cpu/inorder/inorder_cpu_builder.cc (renamed from src/cpu/o3/mips/thread_context.cc)36
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.cc724
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.hh971
-rw-r--r--src/cpu/inorder/inorder_trace.cc94
-rw-r--r--src/cpu/inorder/inorder_trace.hh98
-rw-r--r--[-rwxr-xr-x]src/cpu/inorder/params.hh (renamed from src/cpu/o3/params.hh)148
-rw-r--r--src/cpu/inorder/pipeline_stage.cc1021
-rw-r--r--src/cpu/inorder/pipeline_stage.hh358
-rw-r--r--src/cpu/inorder/pipeline_traits.5stage.cc166
-rw-r--r--src/cpu/inorder/pipeline_traits.5stage.hh147
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.cc242
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.hh155
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.smt2.cc240
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.smt2.hh155
-rw-r--r--src/cpu/inorder/pipeline_traits.cc153
-rw-r--r--src/cpu/inorder/pipeline_traits.hh170
-rw-r--r--src/cpu/inorder/reg_dep_map.cc236
-rw-r--r--src/cpu/inorder/reg_dep_map.hh105
-rw-r--r--src/cpu/inorder/resource.cc434
-rw-r--r--src/cpu/inorder/resource.hh401
-rw-r--r--src/cpu/inorder/resource_pool.9stage.cc357
-rw-r--r--src/cpu/inorder/resource_pool.cc364
-rw-r--r--src/cpu/inorder/resource_pool.hh189
-rw-r--r--src/cpu/inorder/resources/agen_unit.cc98
-rw-r--r--src/cpu/inorder/resources/agen_unit.hh (renamed from src/cpu/o3/mips/params.hh)56
-rw-r--r--src/cpu/inorder/resources/bpred_unit.cc426
-rw-r--r--src/cpu/inorder/resources/bpred_unit.hh258
-rw-r--r--src/cpu/inorder/resources/branch_predictor.cc149
-rw-r--r--src/cpu/inorder/resources/branch_predictor.hh (renamed from src/cpu/o3/sparc/thread_context.hh)88
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc604
-rw-r--r--src/cpu/inorder/resources/cache_unit.hh315
-rw-r--r--src/cpu/inorder/resources/decode_unit.cc92
-rw-r--r--src/cpu/inorder/resources/decode_unit.hh68
-rw-r--r--src/cpu/inorder/resources/execution_unit.cc182
-rw-r--r--src/cpu/inorder/resources/execution_unit.hh (renamed from src/cpu/o3/mips/thread_context.hh)73
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.cc323
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.hh117
-rw-r--r--src/cpu/inorder/resources/graduation_unit.cc112
-rw-r--r--src/cpu/inorder/resources/graduation_unit.hh (renamed from src/cpu/o3/alpha/params.hh)65
-rw-r--r--src/cpu/inorder/resources/inst_buffer.cc222
-rw-r--r--src/cpu/inorder/resources/inst_buffer.hh93
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.cc156
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.hh109
-rw-r--r--src/cpu/inorder/resources/mem_dep_unit.hh (renamed from src/cpu/o3/sparc/params.hh)61
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.cc285
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.hh138
-rw-r--r--[-rwxr-xr-x]src/cpu/inorder/resources/resource_list.hh (renamed from src/cpu/o3/sparc/thread_context.cc)22
-rw-r--r--src/cpu/inorder/resources/tlb_unit.cc188
-rw-r--r--src/cpu/inorder/resources/tlb_unit.hh124
-rw-r--r--src/cpu/inorder/resources/use_def.cc326
-rw-r--r--src/cpu/inorder/resources/use_def.hh102
-rw-r--r--src/cpu/inorder/thread_context.cc264
-rw-r--r--src/cpu/inorder/thread_context.hh275
-rw-r--r--src/cpu/inorder/thread_state.hh90
-rw-r--r--src/cpu/inteltrace.hh11
-rw-r--r--src/cpu/intr_control.cc4
-rw-r--r--src/cpu/legiontrace.hh11
-rw-r--r--src/cpu/memtest/memtest.cc15
-rw-r--r--src/cpu/memtest/memtest.hh29
-rw-r--r--src/cpu/nativetrace.cc6
-rw-r--r--src/cpu/nativetrace.hh12
-rw-r--r--src/cpu/o3/O3CPU.py6
-rw-r--r--src/cpu/o3/O3Checker.py2
-rwxr-xr-xsrc/cpu/o3/SConscript21
-rw-r--r--src/cpu/o3/alpha/cpu.cc38
-rw-r--r--src/cpu/o3/alpha/cpu.hh149
-rw-r--r--src/cpu/o3/alpha/cpu_builder.cc199
-rw-r--r--src/cpu/o3/alpha/cpu_impl.hh314
-rw-r--r--src/cpu/o3/alpha/dyn_inst.cc36
-rw-r--r--src/cpu/o3/alpha/dyn_inst.hh277
-rw-r--r--src/cpu/o3/alpha/impl.hh92
-rw-r--r--src/cpu/o3/base_dyn_inst.cc5
-rw-r--r--src/cpu/o3/bpred_unit.hh25
-rw-r--r--src/cpu/o3/bpred_unit_impl.hh27
-rw-r--r--src/cpu/o3/commit.hh33
-rw-r--r--src/cpu/o3/commit_impl.hh31
-rw-r--r--src/cpu/o3/cpu.cc297
-rw-r--r--src/cpu/o3/cpu.hh148
-rw-r--r--src/cpu/o3/cpu_builder.cc (renamed from src/cpu/o3/alpha/thread_context.hh)72
-rw-r--r--src/cpu/o3/cpu_policy.hh12
-rw-r--r--src/cpu/o3/decode.hh25
-rw-r--r--src/cpu/o3/decode_impl.hh6
-rw-r--r--src/cpu/o3/dyn_inst.cc (renamed from src/cpu/o3/sparc/dyn_inst.cc)8
-rw-r--r--src/cpu/o3/dyn_inst.hh282
-rw-r--r--src/cpu/o3/dyn_inst_impl.hh (renamed from src/cpu/o3/alpha/dyn_inst_impl.hh)63
-rw-r--r--src/cpu/o3/fetch.hh31
-rw-r--r--src/cpu/o3/fetch_impl.hh17
-rw-r--r--src/cpu/o3/iew.hh61
-rw-r--r--src/cpu/o3/iew_impl.hh5
-rw-r--r--src/cpu/o3/impl.hh (renamed from src/cpu/o3/sparc/impl.hh)27
-rw-r--r--src/cpu/o3/inst_queue.hh43
-rw-r--r--src/cpu/o3/inst_queue_impl.hh15
-rwxr-xr-xsrc/cpu/o3/isa_specific.hh20
-rw-r--r--src/cpu/o3/lsq.hh11
-rw-r--r--src/cpu/o3/lsq_impl.hh23
-rw-r--r--src/cpu/o3/lsq_unit.hh33
-rw-r--r--src/cpu/o3/lsq_unit_impl.hh9
-rw-r--r--src/cpu/o3/mem_dep_unit.hh23
-rw-r--r--src/cpu/o3/mem_dep_unit_impl.hh25
-rwxr-xr-xsrc/cpu/o3/mips/cpu.cc39
-rwxr-xr-xsrc/cpu/o3/mips/cpu.hh130
-rw-r--r--src/cpu/o3/mips/cpu_builder.cc182
-rw-r--r--src/cpu/o3/mips/cpu_impl.hh217
-rwxr-xr-xsrc/cpu/o3/mips/dyn_inst.cc37
-rwxr-xr-xsrc/cpu/o3/mips/dyn_inst.hh281
-rwxr-xr-xsrc/cpu/o3/mips/dyn_inst_impl.hh130
-rw-r--r--src/cpu/o3/mips/impl.hh93
-rw-r--r--src/cpu/o3/ras.hh3
-rw-r--r--src/cpu/o3/regfile.hh3
-rw-r--r--src/cpu/o3/rename.hh43
-rw-r--r--src/cpu/o3/rename_impl.hh5
-rw-r--r--src/cpu/o3/sparc/cpu.cc38
-rw-r--r--src/cpu/o3/sparc/cpu.hh148
-rw-r--r--src/cpu/o3/sparc/cpu_builder.cc200
-rw-r--r--src/cpu/o3/sparc/cpu_impl.hh298
-rw-r--r--src/cpu/o3/sparc/dyn_inst.hh265
-rw-r--r--src/cpu/o3/sparc/dyn_inst_impl.hh154
-rwxr-xr-xsrc/cpu/o3/thread_context.cc (renamed from src/cpu/o3/alpha/thread_context.cc)4
-rwxr-xr-xsrc/cpu/o3/thread_context.hh82
-rwxr-xr-xsrc/cpu/o3/thread_context_impl.hh134
-rw-r--r--src/cpu/o3/thread_state.hh8
-rw-r--r--src/cpu/ozone/OzoneCPU.py2
-rw-r--r--src/cpu/ozone/OzoneChecker.py2
-rw-r--r--src/cpu/ozone/back_end.hh100
-rw-r--r--src/cpu/ozone/base_dyn_inst.cc4
-rw-r--r--src/cpu/ozone/cpu.hh96
-rw-r--r--src/cpu/ozone/cpu_impl.hh72
-rw-r--r--src/cpu/ozone/front_end.hh40
-rw-r--r--src/cpu/ozone/front_end_impl.hh4
-rw-r--r--src/cpu/ozone/inorder_back_end.hh16
-rw-r--r--src/cpu/ozone/inorder_back_end_impl.hh3
-rw-r--r--src/cpu/ozone/inst_queue.hh32
-rw-r--r--src/cpu/ozone/lsq_unit.hh2
-rw-r--r--src/cpu/ozone/lsq_unit_impl.hh2
-rw-r--r--src/cpu/ozone/lw_back_end.hh84
-rw-r--r--src/cpu/ozone/lw_back_end_impl.hh5
-rw-r--r--src/cpu/ozone/lw_lsq.hh7
-rw-r--r--src/cpu/pc_event.cc2
-rw-r--r--src/cpu/quiesce_event.cc2
-rw-r--r--src/cpu/simple/AtomicSimpleCPU.py13
-rw-r--r--src/cpu/simple/BaseSimpleCPU.py34
-rw-r--r--src/cpu/simple/SConscript1
-rw-r--r--src/cpu/simple/TimingSimpleCPU.py10
-rw-r--r--src/cpu/simple/atomic.cc280
-rw-r--r--src/cpu/simple/atomic.hh29
-rw-r--r--src/cpu/simple/base.cc71
-rw-r--r--src/cpu/simple/base.hh49
-rw-r--r--src/cpu/simple/timing.cc606
-rw-r--r--src/cpu/simple/timing.hh195
-rw-r--r--src/cpu/simple_thread.cc65
-rw-r--r--src/cpu/simple_thread.hh61
-rw-r--r--src/cpu/static_inst.cc43
-rw-r--r--src/cpu/static_inst.hh172
-rw-r--r--src/cpu/thread_context.cc11
-rw-r--r--src/cpu/thread_context.hh69
-rw-r--r--src/cpu/thread_state.cc24
-rw-r--r--src/cpu/thread_state.hh37
187 files changed, 17510 insertions, 5703 deletions
diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py
index c2a865113..f3688e991 100644
--- a/src/cpu/BaseCPU.py
+++ b/src/cpu/BaseCPU.py
@@ -26,7 +26,7 @@
#
# Authors: Nathan Binkert
-from m5.SimObject import SimObject
+from MemObject import MemObject
from m5.params import *
from m5.proxy import *
from m5 import build_env
@@ -39,50 +39,84 @@ default_tracer = ExeTracer()
if build_env['TARGET_ISA'] == 'alpha':
from AlphaTLB import AlphaDTB, AlphaITB
+ if build_env['FULL_SYSTEM']:
+ from AlphaInterrupts import AlphaInterrupts
elif build_env['TARGET_ISA'] == 'sparc':
from SparcTLB import SparcDTB, SparcITB
+ if build_env['FULL_SYSTEM']:
+ from SparcInterrupts import SparcInterrupts
elif build_env['TARGET_ISA'] == 'x86':
from X86TLB import X86DTB, X86ITB
+ if build_env['FULL_SYSTEM']:
+ from X86LocalApic import X86LocalApic
elif build_env['TARGET_ISA'] == 'mips':
from MipsTLB import MipsTLB,MipsDTB, MipsITB, MipsUTB
+ if build_env['FULL_SYSTEM']:
+ from MipsInterrupts import MipsInterrupts
elif build_env['TARGET_ISA'] == 'arm':
from ArmTLB import ArmTLB, ArmDTB, ArmITB, ArmUTB
+ if build_env['FULL_SYSTEM']:
+ from ArmInterrupts import ArmInterrupts
-class BaseCPU(SimObject):
+class BaseCPU(MemObject):
type = 'BaseCPU'
abstract = True
system = Param.System(Parent.any, "system object")
- cpu_id = Param.Int("CPU identifier")
+ cpu_id = Param.Int(-1, "CPU identifier")
+ numThreads = Param.Unsigned(1, "number of HW thread contexts")
+
+ function_trace = Param.Bool(False, "Enable function trace")
+ function_trace_start = Param.Tick(0, "Cycle to start function trace")
+
+ checker = Param.BaseCPU(NULL, "checker CPU")
+
+ do_checkpoint_insts = Param.Bool(True,
+ "enable checkpoint pseudo instructions")
+ do_statistics_insts = Param.Bool(True,
+ "enable statistics pseudo instructions")
if build_env['FULL_SYSTEM']:
+ profile = Param.Latency('0ns', "trace the kernel stack")
do_quiesce = Param.Bool(True, "enable quiesce instructions")
- do_checkpoint_insts = Param.Bool(True,
- "enable checkpoint pseudo instructions")
- do_statistics_insts = Param.Bool(True,
- "enable statistics pseudo instructions")
else:
workload = VectorParam.Process("processes to run")
if build_env['TARGET_ISA'] == 'sparc':
dtb = Param.SparcDTB(SparcDTB(), "Data TLB")
itb = Param.SparcITB(SparcITB(), "Instruction TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.SparcInterrupts(
+ SparcInterrupts(), "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'alpha':
dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB")
itb = Param.AlphaITB(AlphaITB(), "Instruction TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.AlphaInterrupts(
+ AlphaInterrupts(), "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'x86':
dtb = Param.X86DTB(X86DTB(), "Data TLB")
itb = Param.X86ITB(X86ITB(), "Instruction TLB")
+ if build_env['FULL_SYSTEM']:
+ _localApic = X86LocalApic(pio_addr=0x2000000000000000)
+ interrupts = \
+ Param.X86LocalApic(_localApic, "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'mips':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.MipsDTB(MipsDTB(), "Data TLB")
itb = Param.MipsITB(MipsITB(), "Instruction TLB")
tlb = Param.MipsUTB(MipsUTB(), "Unified TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.MipsInterrupts(
+ MipsInterrupts(), "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'arm':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.ArmDTB(ArmDTB(), "Data TLB")
itb = Param.ArmITB(ArmITB(), "Instruction TLB")
tlb = Param.ArmUTB(ArmUTB(), "Unified TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.ArmInterrupts(
+ ArmInterrupts(), "Interrupt Controller")
else:
print "Don't know what TLB to use for ISA %s" % \
build_env['TARGET_ISA']
@@ -109,7 +143,10 @@ class BaseCPU(SimObject):
_mem_ports = []
if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']:
- _mem_ports = ["itb.walker.port", "dtb.walker.port"]
+ _mem_ports = ["itb.walker.port",
+ "dtb.walker.port",
+ "interrupts.pio",
+ "interrupts.int_port"]
def connectMemPorts(self, bus):
for p in self._mem_ports:
diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py
new file mode 100644
index 000000000..bff9af62d
--- /dev/null
+++ b/src/cpu/CheckerCPU.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2007 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: Nathan Binkert
+
+from m5.params import *
+from m5 import build_env
+from BaseCPU import BaseCPU
+
+class CheckerCPU(BaseCPU):
+ type = 'CheckerCPU'
+ abstract = True
+ exitOnError = Param.Bool(False, "Exit on an error")
+ updateOnError = Param.Bool(False,
+ "Update the checker with the main CPU's state on an error")
+ warnOnlyOnLoadError = Param.Bool(False,
+ "If a load result is incorrect, only print a warning and do not exit")
+ function_trace = Param.Bool(False, "Enable function trace")
+ function_trace_start = Param.Tick(0, "Cycle to start function trace")
diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py
index e904f9e7d..5754f5d5b 100644
--- a/src/cpu/ExeTracer.py
+++ b/src/cpu/ExeTracer.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class ExeTracer(InstTracer):
type = 'ExeTracer'
- cxx_namespace = 'Trace'
- cxx_class = 'ExeTracer'
+ cxx_class = 'Trace::ExeTracer'
diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py
index 6e8f567b3..3642f3174 100644
--- a/src/cpu/IntelTrace.py
+++ b/src/cpu/IntelTrace.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class IntelTrace(InstTracer):
type = 'IntelTrace'
- cxx_namespace = 'Trace'
- cxx_class = 'IntelTrace'
+ cxx_class = 'Trace::IntelTrace'
diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py
index f9b6470a6..d450dd00e 100644
--- a/src/cpu/LegionTrace.py
+++ b/src/cpu/LegionTrace.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class LegionTrace(InstTracer):
type = 'LegionTrace'
- cxx_namespace = 'Trace'
- cxx_class = 'LegionTrace'
+ cxx_class = 'Trace::LegionTrace'
diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py
index 96b4e991b..f410b5473 100644
--- a/src/cpu/NativeTrace.py
+++ b/src/cpu/NativeTrace.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class NativeTrace(InstTracer):
type = 'NativeTrace'
- cxx_namespace = 'Trace'
- cxx_class = 'NativeTrace'
+ cxx_class = 'Trace::NativeTrace'
diff --git a/src/cpu/SConscript b/src/cpu/SConscript
index c7d0c33bd..eee8edca4 100644
--- a/src/cpu/SConscript
+++ b/src/cpu/SConscript
@@ -48,12 +48,14 @@ execfile(models_db.srcnode().abspath)
# Template for execute() signature.
exec_sig_template = '''
-virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0;
-virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const
+virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0;
+virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const
{ panic("initiateAcc not defined!"); M5_DUMMY_RETURN };
-virtual Fault completeAcc(Packet *pkt, %s *xc,
+virtual Fault completeAcc(Packet *pkt, %(type)s *xc,
Trace::InstRecord *traceData) const
{ panic("completeAcc not defined!"); M5_DUMMY_RETURN };
+virtual int memAccSize(%(type)s *xc)
+{ panic("memAccSize not defined!"); M5_DUMMY_RETURN };
'''
mem_ini_sig_template = '''
@@ -71,6 +73,7 @@ temp_cpu_list = env['CPU_MODELS'][:]
if env['USE_CHECKER']:
temp_cpu_list.append('CheckerCPU')
+ SimObject('CheckerCPU.py')
# Generate header.
def gen_cpu_exec_signatures(target, source, env):
@@ -81,7 +84,7 @@ def gen_cpu_exec_signatures(target, source, env):
'''
for cpu in temp_cpu_list:
xc_type = CpuModel.dict[cpu].strings['CPU_exec_context']
- print >> f, exec_sig_template % (xc_type, xc_type, xc_type)
+ print >> f, exec_sig_template % { 'type' : xc_type }
print >> f, '''
#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__
'''
@@ -165,10 +168,12 @@ TraceFlag('ExecSpeculative')
TraceFlag('ExecSymbol')
TraceFlag('ExecThread')
TraceFlag('ExecTicks')
+TraceFlag('ExecMicro')
+TraceFlag('ExecMacro')
TraceFlag('Fetch')
TraceFlag('IntrControl')
TraceFlag('PCEvent')
TraceFlag('Quiesce')
CompoundFlag('Exec', [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', 'ExecThread',
- 'ExecEffAddr', 'ExecResult', 'ExecSymbol' ])
+ 'ExecEffAddr', 'ExecResult', 'ExecSymbol', 'ExecMicro' ])
diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc
index 15e0556ad..a2a34edf9 100644
--- a/src/cpu/activity.cc
+++ b/src/cpu/activity.cc
@@ -28,15 +28,18 @@
* Authors: Kevin Lim
*/
-#include <cstring>
+#include <string>
#include "base/timebuf.hh"
#include "cpu/activity.hh"
-ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency,
- int activity)
- : activityBuffer(longest_latency, 0), longestLatency(longest_latency),
- activityCount(activity), numStages(num_stages)
+using namespace std;
+
+ActivityRecorder::ActivityRecorder(const string &name, int num_stages,
+ int longest_latency, int activity)
+ : _name(name), activityBuffer(longest_latency, 0),
+ longestLatency(longest_latency), activityCount(activity),
+ numStages(num_stages)
{
stageActive = new bool[numStages];
std::memset(stageActive, 0, numStages);
diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh
index e99927339..d75ff150e 100644
--- a/src/cpu/activity.hh
+++ b/src/cpu/activity.hh
@@ -49,9 +49,11 @@
* idle. If count is zero, then the CPU can safely idle as it has no
* more outstanding work to do.
*/
-class ActivityRecorder {
+class ActivityRecorder
+{
public:
- ActivityRecorder(int num_stages, int longest_latency, int count);
+ ActivityRecorder(const std::string &name, int num_stages,
+ int longest_latency, int count);
/** Records that there is activity this cycle. */
void activity();
@@ -92,6 +94,10 @@ class ActivityRecorder {
void validate();
private:
+ // provide name() for DPRINTF.
+ std::string _name;
+ const std::string &name() { return _name; }
+
/** Time buffer that tracks if any cycles has active communication
* in them. It should be as long as the longest communication
* latency in the system. Each time any time buffer is written,
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
index 23195f720..0ef206d90 100644
--- a/src/cpu/base.cc
+++ b/src/cpu/base.cc
@@ -37,17 +37,17 @@
#include "base/loader/symtab.hh"
#include "base/misc.hh"
#include "base/output.hh"
+#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/cpuevent.hh"
#include "cpu/thread_context.hh"
#include "cpu/profile.hh"
+#include "params/BaseCPU.hh"
#include "sim/sim_exit.hh"
#include "sim/process.hh"
#include "sim/sim_events.hh"
#include "sim/system.hh"
-#include "base/trace.hh"
-
// Hack
#include "sim/stat_control.hh"
@@ -60,13 +60,12 @@ vector<BaseCPU *> BaseCPU::cpuList;
// been initialized
int maxThreadsPerCPU = 1;
-CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival,
- BaseCPU *_cpu)
- : Event(q, Event::Progress_Event_Pri), interval(ival),
- lastNumInst(0), cpu(_cpu)
+CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
+ : Event(Event::Progress_Event_Pri), interval(ival), lastNumInst(0),
+ cpu(_cpu)
{
if (interval)
- schedule(curTick + interval);
+ cpu->schedule(this, curTick + interval);
}
void
@@ -84,7 +83,7 @@ CPUProgressEvent::process()
curTick, cpu->name(), temp - lastNumInst);
#endif
lastNumInst = temp;
- schedule(curTick + interval);
+ cpu->schedule(this, curTick + interval);
}
const char *
@@ -95,21 +94,29 @@ CPUProgressEvent::description() const
#if FULL_SYSTEM
BaseCPU::BaseCPU(Params *p)
- : MemObject(makeParams(p->name)), clock(p->clock), instCnt(0),
- params(p), number_of_threads(p->numberOfThreads), system(p->system),
+ : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id),
+ interrupts(p->interrupts),
+ number_of_threads(p->numThreads), system(p->system),
phase(p->phase)
#else
BaseCPU::BaseCPU(Params *p)
- : MemObject(makeParams(p->name)), clock(p->clock), params(p),
- number_of_threads(p->numberOfThreads), system(p->system),
+ : MemObject(p), clock(p->clock), _cpuId(p->cpu_id),
+ number_of_threads(p->numThreads), system(p->system),
phase(p->phase)
#endif
{
// currentTick = curTick;
+ // if Python did not provide a valid ID, do it here
+ if (_cpuId == -1 ) {
+ _cpuId = cpuList.size();
+ }
+
// add self to global list of CPUs
cpuList.push_back(this);
+ DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId);
+
if (number_of_threads > maxThreadsPerCPU)
maxThreadsPerCPU = number_of_threads;
@@ -121,22 +128,26 @@ BaseCPU::BaseCPU(Params *p)
//
// set up instruction-count-based termination events, if any
//
- if (p->max_insts_any_thread != 0)
- for (int i = 0; i < number_of_threads; ++i)
- schedExitSimLoop("a thread reached the max instruction count",
- p->max_insts_any_thread, 0,
- comInstEventQueue[i]);
+ if (p->max_insts_any_thread != 0) {
+ const char *cause = "a thread reached the max instruction count";
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new SimLoopExitEvent(cause, 0);
+ comInstEventQueue[i]->schedule(event, p->max_insts_any_thread);
+ }
+ }
if (p->max_insts_all_threads != 0) {
+ const char *cause = "all threads reached the max instruction count";
+
// allocate & initialize shared downcounter: each event will
// decrement this when triggered; simulation will terminate
// when counter reaches 0
int *counter = new int;
*counter = number_of_threads;
- for (int i = 0; i < number_of_threads; ++i)
- new CountedExitEvent(comInstEventQueue[i],
- "all threads reached the max instruction count",
- p->max_insts_all_threads, *counter);
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new CountedExitEvent(cause, *counter);
+ comInstEventQueue[i]->schedule(event, p->max_insts_any_thread);
+ }
}
// allocate per-thread load-based event queues
@@ -147,53 +158,49 @@ BaseCPU::BaseCPU(Params *p)
//
// set up instruction-count-based termination events, if any
//
- if (p->max_loads_any_thread != 0)
- for (int i = 0; i < number_of_threads; ++i)
- schedExitSimLoop("a thread reached the max load count",
- p->max_loads_any_thread, 0,
- comLoadEventQueue[i]);
+ if (p->max_loads_any_thread != 0) {
+ const char *cause = "a thread reached the max load count";
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new SimLoopExitEvent(cause, 0);
+ comLoadEventQueue[i]->schedule(event, p->max_loads_any_thread);
+ }
+ }
if (p->max_loads_all_threads != 0) {
+ const char *cause = "all threads reached the max load count";
// allocate & initialize shared downcounter: each event will
// decrement this when triggered; simulation will terminate
// when counter reaches 0
int *counter = new int;
*counter = number_of_threads;
- for (int i = 0; i < number_of_threads; ++i)
- new CountedExitEvent(comLoadEventQueue[i],
- "all threads reached the max load count",
- p->max_loads_all_threads, *counter);
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new CountedExitEvent(cause, *counter);
+ comLoadEventQueue[i]->schedule(event, p->max_loads_all_threads);
+ }
}
functionTracingEnabled = false;
- if (p->functionTrace) {
+ if (p->function_trace) {
functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
currentFunctionStart = currentFunctionEnd = 0;
- functionEntryTick = p->functionTraceStart;
+ functionEntryTick = p->function_trace_start;
- if (p->functionTraceStart == 0) {
+ if (p->function_trace_start == 0) {
functionTracingEnabled = true;
} else {
- new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
- p->functionTraceStart,
- true);
+ typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap;
+ Event *event = new wrap(this, true);
+ schedule(event, p->function_trace_start);
}
}
#if FULL_SYSTEM
- profileEvent = NULL;
- if (params->profile)
- profileEvent = new ProfileEvent(this, params->profile);
-#endif
- tracer = params->tracer;
-}
+ interrupts->setCPU(this);
-BaseCPU::Params::Params()
-{
-#if FULL_SYSTEM
- profile = false;
+ profileEvent = NULL;
+ if (params()->profile)
+ profileEvent = new ProfileEvent(this, params()->profile);
#endif
- checker = NULL;
- tracer = NULL;
+ tracer = params()->tracer;
}
void
@@ -209,7 +216,7 @@ BaseCPU::~BaseCPU()
void
BaseCPU::init()
{
- if (!params->deferRegistration)
+ if (!params()->defer_registration)
registerThreadContexts();
}
@@ -217,14 +224,14 @@ void
BaseCPU::startup()
{
#if FULL_SYSTEM
- if (!params->deferRegistration && profileEvent)
- profileEvent->schedule(curTick);
+ if (!params()->defer_registration && profileEvent)
+ schedule(profileEvent, curTick);
#endif
- if (params->progress_interval) {
- new CPUProgressEvent(&mainEventQueue,
- ticks(params->progress_interval),
- this);
+ if (params()->progress_interval) {
+ Tick num_ticks = ticks(params()->progress_interval);
+ Event *event = new CPUProgressEvent(this, num_ticks);
+ schedule(event, curTick + num_ticks);
}
}
@@ -280,14 +287,19 @@ BaseCPU::registerThreadContexts()
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
-#if FULL_SYSTEM
- int id = params->cpu_id;
- if (id != -1)
- id += i;
-
- tc->setCpuId(system->registerThreadContext(tc, id));
-#else
- tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc));
+ /** This is so that contextId and cpuId match where there is a
+ * 1cpu:1context relationship. Otherwise, the order of registration
+ * could affect the assignment and cpu 1 could have context id 3, for
+ * example. We may even want to do something like this for SMT so that
+ * cpu 0 has the lowest thread contexts and cpu N has the highest, but
+ * I'll just do this for now
+ */
+ if (number_of_threads == 1)
+ tc->setContextId(system->registerThreadContext(tc, _cpuId));
+ else
+ tc->setContextId(system->registerThreadContext(tc));
+#if !FULL_SYSTEM
+ tc->getProcessPtr()->assignThreadContext(tc->contextId());
#endif
}
}
@@ -309,7 +321,7 @@ BaseCPU::switchOut()
// panic("This CPU doesn't support sampling!");
#if FULL_SYSTEM
if (profileEvent && profileEvent->scheduled())
- profileEvent->deschedule();
+ deschedule(profileEvent);
#endif
}
@@ -318,6 +330,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
{
assert(threadContexts.size() == oldCPU->threadContexts.size());
+ _cpuId = oldCPU->cpuId();
+
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *newTC = threadContexts[i];
ThreadContext *oldTC = oldCPU->threadContexts[i];
@@ -326,53 +340,49 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
CpuEvent::replaceThreadContext(oldTC, newTC);
- assert(newTC->readCpuId() == oldTC->readCpuId());
-#if FULL_SYSTEM
- system->replaceThreadContext(newTC, newTC->readCpuId());
-#else
- assert(newTC->getProcessPtr() == oldTC->getProcessPtr());
- newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId());
-#endif
+ assert(newTC->contextId() == oldTC->contextId());
+ assert(newTC->threadId() == oldTC->threadId());
+ system->replaceThreadContext(newTC, newTC->contextId());
- if (DTRACE(Context))
+ /* This code no longer works since the zero register (e.g.,
+ * r31 on Alpha) doesn't necessarily contain zero at this
+ * point.
+ if (DTRACE(Context))
ThreadContext::compare(oldTC, newTC);
+ */
}
#if FULL_SYSTEM
interrupts = oldCPU->interrupts;
+ interrupts->setCPU(this);
for (int i = 0; i < threadContexts.size(); ++i)
threadContexts[i]->profileClear();
if (profileEvent)
- profileEvent->schedule(curTick);
+ schedule(profileEvent, curTick);
#endif
// Connect new CPU to old CPU's memory only if new CPU isn't
// connected to anything. Also connect old CPU's memory to new
// CPU.
- Port *peer;
- if (ic->getPeer() == NULL || ic->getPeer()->isDefaultPort()) {
- peer = oldCPU->getPort("icache_port")->getPeer();
+ if (!ic->isConnected()) {
+ Port *peer = oldCPU->getPort("icache_port")->getPeer();
ic->setPeer(peer);
- } else {
- peer = ic->getPeer();
+ peer->setPeer(ic);
}
- peer->setPeer(ic);
- if (dc->getPeer() == NULL || dc->getPeer()->isDefaultPort()) {
- peer = oldCPU->getPort("dcache_port")->getPeer();
+ if (!dc->isConnected()) {
+ Port *peer = oldCPU->getPort("dcache_port")->getPeer();
dc->setPeer(peer);
- } else {
- peer = dc->getPeer();
+ peer->setPeer(dc);
}
- peer->setPeer(dc);
}
#if FULL_SYSTEM
-BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
- : Event(&mainEventQueue), cpu(_cpu), interval(_interval)
+BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval)
+ : cpu(_cpu), interval(_interval)
{ }
void
@@ -383,45 +393,21 @@ BaseCPU::ProfileEvent::process()
tc->profileSample();
}
- schedule(curTick + interval);
-}
-
-void
-BaseCPU::post_interrupt(int int_num, int index)
-{
- interrupts.post(int_num, index);
-}
-
-void
-BaseCPU::clear_interrupt(int int_num, int index)
-{
- interrupts.clear(int_num, index);
-}
-
-void
-BaseCPU::clear_interrupts()
-{
- interrupts.clear_all();
-}
-
-uint64_t
-BaseCPU::get_interrupts(int int_num)
-{
- return interrupts.get_vec(int_num);
+ cpu->schedule(this, curTick + interval);
}
void
BaseCPU::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(instCnt);
- interrupts.serialize(os);
+ interrupts->serialize(os);
}
void
BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(instCnt);
- interrupts.unserialize(cp, section);
+ interrupts->unserialize(cp, section);
}
#endif // FULL_SYSTEM
diff --git a/src/cpu/base.hh b/src/cpu/base.hh
index bdc7d7c8b..8af3295eb 100644
--- a/src/cpu/base.hh
+++ b/src/cpu/base.hh
@@ -35,6 +35,7 @@
#include <vector>
#include "arch/isa_traits.hh"
+#include "arch/microcode_rom.hh"
#include "base/statistics.hh"
#include "config/full_system.hh"
#include "sim/eventq.hh"
@@ -45,6 +46,7 @@
#include "arch/interrupts.hh"
#endif
+class BaseCPUParams;
class BranchPred;
class CheckerCPU;
class ThreadContext;
@@ -64,7 +66,7 @@ class CPUProgressEvent : public Event
BaseCPU *cpu;
public:
- CPUProgressEvent(EventQueue *q, Tick ival, BaseCPU *_cpu);
+ CPUProgressEvent(BaseCPU *_cpu, Tick ival);
void process();
@@ -78,8 +80,16 @@ class BaseCPU : public MemObject
Tick clock;
// @todo remove me after debugging with legion done
Tick instCnt;
+ // every cpu has an id, put it in the base cpu
+ // Set at initialization, only time a cpuId might change is during a
+ // takeover (which should be done from within the BaseCPU anyway,
+ // therefore no setCpuId() method is provided
+ int _cpuId;
public:
+ /** Reads this CPU's ID. */
+ int cpuId() { return _cpuId; }
+
// Tick currentTick;
inline Tick frequency() const { return Clock::Frequency / clock; }
inline Tick ticks(int numCycles) const { return clock * numCycles; }
@@ -102,29 +112,54 @@ class BaseCPU : public MemObject
*/
Tick nextCycle(Tick begin_tick);
+ TheISA::MicrocodeRom microcodeRom;
+
#if FULL_SYSTEM
protected:
-// uint64_t interrupts[TheISA::NumInterruptLevels];
-// uint64_t intstatus;
- TheISA::Interrupts interrupts;
+ TheISA::Interrupts *interrupts;
public:
- virtual void post_interrupt(int int_num, int index);
- virtual void clear_interrupt(int int_num, int index);
- virtual void clear_interrupts();
- virtual uint64_t get_interrupts(int int_num);
+ TheISA::Interrupts *
+ getInterruptController()
+ {
+ return interrupts;
+ }
+
+ virtual void wakeup() = 0;
+
+ void
+ postInterrupt(int int_num, int index)
+ {
+ interrupts->post(int_num, index);
+ wakeup();
+ }
+
+ void
+ clearInterrupt(int int_num, int index)
+ {
+ interrupts->clear(int_num, index);
+ }
+
+ void
+ clearInterrupts()
+ {
+ interrupts->clearAll();
+ }
- bool check_interrupts(ThreadContext * tc) const
- { return interrupts.check_interrupts(tc); }
+ bool
+ checkInterrupts(ThreadContext *tc) const
+ {
+ return interrupts->checkInterrupts(tc);
+ }
class ProfileEvent : public Event
{
private:
BaseCPU *cpu;
- int interval;
+ Tick interval;
public:
- ProfileEvent(BaseCPU *cpu, int interval);
+ ProfileEvent(BaseCPU *cpu, Tick interval);
void process();
};
ProfileEvent *profileEvent;
@@ -162,40 +197,9 @@ class BaseCPU : public MemObject
ThreadContext *getContext(int tn) { return threadContexts[tn]; }
public:
- struct Params
- {
- std::string name;
- int numberOfThreads;
- bool deferRegistration;
- Counter max_insts_any_thread;
- Counter max_insts_all_threads;
- Counter max_loads_any_thread;
- Counter max_loads_all_threads;
- Tick clock;
- bool functionTrace;
- Tick functionTraceStart;
- System *system;
- int cpu_id;
- Trace::InstTracer * tracer;
-
- Tick phase;
-#if FULL_SYSTEM
- Tick profile;
-
- bool do_statistics_insts;
- bool do_checkpoint_insts;
- bool do_quiesce;
-#endif
- Tick progress_interval;
- BaseCPU *checker;
-
- TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core
-
- Params();
- };
-
- const Params *params;
-
+ typedef BaseCPUParams Params;
+ const Params *params() const
+ { return reinterpret_cast<const Params *>(_params); }
BaseCPU(Params *params);
virtual ~BaseCPU();
@@ -221,6 +225,8 @@ class BaseCPU : public MemObject
*/
int number_of_threads;
+ TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core
+
/**
* Vector of per-thread instruction-based event queues. Used for
* scheduling events based on number of instructions committed by
@@ -298,7 +304,7 @@ class BaseCPU : public MemObject
public:
// Number of CPU cycles simulated
- Stats::Scalar<> numCycles;
+ Stats::Scalar numCycles;
};
#endif // __CPU_BASE_HH__
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh
index bea680fac..41c57cf39 100644
--- a/src/cpu/base_dyn_inst.hh
+++ b/src/cpu/base_dyn_inst.hh
@@ -77,8 +77,8 @@ class BaseDynInst : public FastAlloc, public RefCounted
typedef typename std::list<DynInstPtr>::iterator ListIt;
enum {
- MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs
- MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs
};
/** The StaticInst used by this BaseDynInst. */
@@ -115,9 +115,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
- Fault translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
/**
* Does a write to a given address.
* @param data The data to be written.
@@ -130,9 +127,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
Fault write(T data, Addr addr, unsigned flags,
uint64_t *res);
- Fault translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
void prefetch(Addr addr, unsigned flags);
void writeHint(Addr addr, int size, unsigned flags);
Fault copySrcTranslate(Addr src);
@@ -258,9 +252,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
public:
- /** Count of total number of dynamic instructions. */
- static int instcount;
-
#ifdef DEBUG
void dumpSNList();
#endif
@@ -412,7 +403,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
void dump(std::string &outstring);
/** Read this CPU's ID. */
- int readCpuId() { return cpu->readCpuId(); }
+ int cpuId() { return cpu->cpuId(); }
+
+ /** Read this context's system-wide ID **/
+ int contextId() { return thread->contextId(); }
/** Returns the fault type. */
Fault getFault() { return fault; }
@@ -486,24 +480,24 @@ class BaseDynInst : public FastAlloc, public RefCounted
//
// 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 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 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 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(); }
@@ -560,7 +554,7 @@ class BaseDynInst : public FastAlloc, public RefCounted
Addr branchTarget() const { return staticInst->branchTarget(PC); }
/** Returns the number of source registers. */
- int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
+ int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
/** Returns the number of destination registers. */
int8_t numDestRegs() const { return staticInst->numDestRegs(); }
@@ -857,29 +851,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
};
template<class Impl>
-Fault
-BaseDynInst<Impl>::translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- reqMade = true;
- Request *req = new Request();
- req->setVirt(asid, vaddr, size, flags, PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
-
- fault = cpu->translateDataReadReq(req, thread);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
-}
-
-template<class Impl>
template<class T>
inline Fault
BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
@@ -887,9 +858,9 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
reqMade = true;
Request *req = new Request();
req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
+ req->setThreadContext(thread->contextId(), threadNumber);
- fault = cpu->translateDataReadReq(req, thread);
+ fault = cpu->dtb->translateAtomic(req, thread->getTC(), false);
if (req->isUncacheable())
isUncacheable = true;
@@ -931,29 +902,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
}
template<class Impl>
-Fault
-BaseDynInst<Impl>::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- reqMade = true;
- Request *req = new Request();
- req->setVirt(asid, vaddr, size, flags, PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
-
- fault = cpu->translateDataWriteReq(req, thread);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
-}
-
-template<class Impl>
template<class T>
inline Fault
BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
@@ -966,9 +914,9 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
reqMade = true;
Request *req = new Request();
req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
+ req->setThreadContext(thread->contextId(), threadNumber);
- fault = cpu->translateDataWriteReq(req, thread);
+ fault = cpu->dtb->translateAtomic(req, thread->getTC(), true);
if (req->isUncacheable())
isUncacheable = true;
diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh
index 5c18ae694..4ee7d2f2c 100644
--- a/src/cpu/base_dyn_inst_impl.hh
+++ b/src/cpu/base_dyn_inst_impl.hh
@@ -168,18 +168,21 @@ BaseDynInst<Impl>::initVars()
// Initialize the fault to be NoFault.
fault = NoFault;
- ++instcount;
+#ifndef NDEBUG
+ ++cpu->instcount;
- if (instcount > 1500) {
- cpu->dumpInsts();
+ if (cpu->instcount > 1500) {
#ifdef DEBUG
+ cpu->dumpInsts();
dumpSNList();
#endif
- assert(instcount <= 1500);
+ assert(cpu->instcount <= 1500);
}
- DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n",
- seqNum, instcount);
+ DPRINTF(DynInst,
+ "DynInst: [sn:%lli] Instruction created. Instcount for %s = %i\n",
+ seqNum, cpu->name(), cpu->instcount);
+#endif
#ifdef DEBUG
cpu->snList.insert(seqNum);
@@ -199,10 +202,13 @@ BaseDynInst<Impl>::~BaseDynInst()
fault = NoFault;
- --instcount;
+#ifndef NDEBUG
+ --cpu->instcount;
- DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n",
- seqNum, instcount);
+ DPRINTF(DynInst,
+ "DynInst: [sn:%lli] Instruction destroyed. Instcount for %s = %i\n",
+ seqNum, cpu->name(), cpu->instcount);
+#endif
#ifdef DEBUG
cpu->snList.erase(seqNum);
#endif
diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc
index a6af98d66..14777bc12 100644
--- a/src/cpu/checker/cpu.cc
+++ b/src/cpu/checker/cpu.cc
@@ -159,7 +159,7 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags)
memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
// translate to physical address
- translateDataReadReq(memReq);
+ dtb->translateAtomic(memReq, tc, false);
PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
@@ -229,7 +229,7 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
// translate to physical address
- thread->translateDataWriteReq(memReq);
+ dtb->translateAtomic(memReq, tc, true);
// Can compare the write data and result only if it's cacheable,
// not a store conditional, or is a store conditional that
@@ -325,57 +325,6 @@ CheckerCPU::dbg_vtophys(Addr addr)
#endif // FULL_SYSTEM
bool
-CheckerCPU::translateInstReq(Request *req)
-{
-#if FULL_SYSTEM
- return (thread->translateInstReq(req) == NoFault);
-#else
- thread->translateInstReq(req);
- return true;
-#endif
-}
-
-void
-CheckerCPU::translateDataReadReq(Request *req)
-{
- thread->translateDataReadReq(req);
-
- if (req->getVaddr() != unverifiedReq->getVaddr()) {
- warn("%lli: Request virtual addresses do not match! Inst: %#x, "
- "checker: %#x",
- curTick, unverifiedReq->getVaddr(), req->getVaddr());
- handleError();
- }
- req->setPaddr(unverifiedReq->getPaddr());
-
- if (checkFlags(req)) {
- warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
- curTick, unverifiedReq->getFlags(), req->getFlags());
- handleError();
- }
-}
-
-void
-CheckerCPU::translateDataWriteReq(Request *req)
-{
- thread->translateDataWriteReq(req);
-
- if (req->getVaddr() != unverifiedReq->getVaddr()) {
- warn("%lli: Request virtual addresses do not match! Inst: %#x, "
- "checker: %#x",
- curTick, unverifiedReq->getVaddr(), req->getVaddr());
- handleError();
- }
- req->setPaddr(unverifiedReq->getPaddr());
-
- if (checkFlags(req)) {
- warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
- curTick, unverifiedReq->getFlags(), req->getFlags());
- handleError();
- }
-}
-
-bool
CheckerCPU::checkFlags(Request *req)
{
// Remove any dynamic flags that don't have to do with the request itself.
diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh
index 35dc59ff4..0d3dddded 100644
--- a/src/cpu/checker/cpu.hh
+++ b/src/cpu/checker/cpu.hh
@@ -65,6 +65,7 @@ class Process;
#endif // FULL_SYSTEM
template <class>
class BaseDynInst;
+class CheckerCPUParams;
class ThreadContext;
class MemInterface;
class Checkpoint;
@@ -96,20 +97,10 @@ class CheckerCPU : public BaseCPU
public:
virtual void init();
- struct Params : public BaseCPU::Params
- {
-#if FULL_SYSTEM
- TheISA::ITB *itb;
- TheISA::DTB *dtb;
-#else
- Process *process;
-#endif
- bool exitOnError;
- bool updateOnError;
- bool warnOnlyOnLoadError;
- };
-
public:
+ typedef CheckerCPUParams Params;
+ const Params *params() const
+ { return reinterpret_cast<const Params *>(_params); }
CheckerCPU(Params *p);
virtual ~CheckerCPU();
@@ -189,7 +180,7 @@ class CheckerCPU : public BaseCPU
// These functions are only used in CPU models that split
// effective address computation from the actual memory access.
void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
- Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
+ Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
void prefetch(Addr addr, unsigned flags)
{
@@ -340,10 +331,6 @@ class CheckerCPU : public BaseCPU
this->dtb->demapPage(vaddr, asn);
}
- bool translateInstReq(Request *req);
- void translateDataWriteReq(Request *req);
- void translateDataReadReq(Request *req);
-
#if FULL_SYSTEM
Fault hwrei() { return thread->hwrei(); }
void ev5_trap(Fault fault) { fault->invoke(tc); }
diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh
index f3f8a0bb3..26571ed68 100644
--- a/src/cpu/checker/cpu_impl.hh
+++ b/src/cpu/checker/cpu_impl.hh
@@ -141,9 +141,9 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
// Try to fetch the instruction
#if FULL_SYSTEM
-#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
+#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
#else
-#define IFETCH_FLAGS(pc) 0
+#define IFETCH_FLAGS(pc) 0
#endif
uint64_t fetch_PC = thread->readPC() & ~3;
@@ -152,9 +152,10 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
memReq = new Request(inst->threadNumber, fetch_PC,
sizeof(uint32_t),
IFETCH_FLAGS(thread->readPC()),
- fetch_PC, thread->readCpuId(), inst->threadNumber);
+ fetch_PC, thread->contextId(),
+ inst->threadNumber);
- bool succeeded = translateInstReq(memReq);
+ bool succeeded = itb->translateAtomic(memReq, thread);
if (!succeeded) {
if (inst->getFault() == NoFault) {
diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh
index 15454c3fe..3c87f841f 100644
--- a/src/cpu/checker/thread_context.hh
+++ b/src/cpu/checker/thread_context.hh
@@ -82,7 +82,7 @@ class CheckerThreadContext : public ThreadContext
checkerTC->setCpuId(id);
}
- int readCpuId() { return actualTC->readCpuId(); }
+ int cpuId() { return actualTC->cpuId(); }
TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); }
@@ -98,10 +98,8 @@ class CheckerThreadContext : public ThreadContext
FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL)
+ VirtualPort *getVirtPort()
{ return actualTC->getVirtPort(); }
-
- void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); }
#else
TranslatingPort *getMemPort() { return actualTC->getMemPort(); }
@@ -155,7 +153,7 @@ class CheckerThreadContext : public ThreadContext
void profileSample() { return actualTC->profileSample(); }
#endif
- int getThreadNum() { return actualTC->getThreadNum(); }
+ int threadId() { return actualTC->threadId(); }
// @todo: Do I need this?
MachInst getInst() { return actualTC->getInst(); }
@@ -279,29 +277,8 @@ class CheckerThreadContext : public ThreadContext
bool misspeculating() { return actualTC->misspeculating(); }
#if !FULL_SYSTEM
- IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, IntReg val)
- {
- checkerTC->setSyscallArg(i, val);
- actualTC->setSyscallArg(i, val);
- }
-
- void setSyscallReturn(SyscallReturn return_value)
- {
- checkerTC->setSyscallReturn(return_value);
- actualTC->setSyscallReturn(return_value);
- }
-
Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
#endif
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- actualTC->changeRegFileContext(param, val);
- checkerTC->changeRegFileContext(param, val);
- }
};
#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__
diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py
index 5b0c6c4da..793f8c646 100644
--- a/src/cpu/cpu_models.py
+++ b/src/cpu/cpu_models.py
@@ -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/cpuevent.hh b/src/cpu/cpuevent.hh
index 5816c6ca1..65f0e87e1 100644
--- a/src/cpu/cpuevent.hh
+++ b/src/cpu/cpuevent.hh
@@ -58,8 +58,8 @@ class CpuEvent : public Event
ThreadContext *tc;
public:
- CpuEvent(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri)
- : Event(q, p), tc(_tc)
+ CpuEvent(ThreadContext *_tc, Priority p = Default_Pri)
+ : Event(p), tc(_tc)
{ cpuEventList.push_back(this); }
/** delete the cpu event from the global list. */
@@ -81,9 +81,8 @@ class CpuEventWrapper : public CpuEvent
T *object;
public:
- CpuEventWrapper(T *obj, ThreadContext *_tc,
- EventQueue *q = &mainEventQueue, Priority p = Default_Pri)
- : CpuEvent(q, _tc, p), object(obj)
+ CpuEventWrapper(T *obj, ThreadContext *_tc, Priority p = Default_Pri)
+ : CpuEvent(_tc, p), object(obj)
{ }
void process() { (object->*F)(tc); }
};
diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc
index 0118dbde1..ea53fb6f5 100644
--- a/src/cpu/exetrace.cc
+++ b/src/cpu/exetrace.cc
@@ -46,12 +46,18 @@ using namespace TheISA;
namespace Trace {
void
-Trace::ExeTracerRecord::dump()
+ExeTracerRecord::dumpTicks(ostream &outs)
+{
+ ccprintf(outs, "%7d: ", when);
+}
+
+void
+Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran)
{
ostream &outs = Trace::output();
if (IsOn(ExecTicks))
- ccprintf(outs, "%7d: ", when);
+ dumpTicks(outs);
outs << thread->getCpuPtr()->name() << " ";
@@ -59,46 +65,59 @@ Trace::ExeTracerRecord::dump()
outs << (misspeculating ? "-" : "+") << " ";
if (IsOn(ExecThread))
- outs << "T" << thread->getThreadNum() << " : ";
-
+ outs << "T" << thread->threadId() << " : ";
std::string sym_str;
Addr sym_addr;
if (debugSymbolTable
&& IsOn(ExecSymbol)
+#if FULL_SYSTEM
+ && !inUserMode(thread)
+#endif
&& debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) {
if (PC != sym_addr)
sym_str += csprintf("+%d", PC - sym_addr);
- outs << "@" << sym_str << " : ";
+ outs << "@" << sym_str;
}
else {
- outs << "0x" << hex << PC << " : ";
+ outs << "0x" << hex << PC;
}
+ if (inst->isMicroop()) {
+ outs << "." << setw(2) << dec << upc;
+ } else {
+ outs << " ";
+ }
+
+ outs << " : ";
+
//
// Print decoded instruction
//
outs << setw(26) << left;
- outs << staticInst->disassemble(PC, debugSymbolTable);
- outs << " : ";
+ outs << inst->disassemble(PC, debugSymbolTable);
- if (IsOn(ExecOpClass)) {
- outs << Enums::OpClassStrings[staticInst->opClass()] << " : ";
- }
+ if (ran) {
+ outs << " : ";
- if (IsOn(ExecResult) && data_status != DataInvalid) {
- ccprintf(outs, " D=%#018x", data.as_int);
- }
+ if (IsOn(ExecOpClass)) {
+ outs << Enums::OpClassStrings[inst->opClass()] << " : ";
+ }
+
+ if (IsOn(ExecResult) && data_status != DataInvalid) {
+ ccprintf(outs, " D=%#018x", data.as_int);
+ }
- if (IsOn(ExecEffAddr) && addr_valid)
- outs << " A=0x" << hex << addr;
+ if (IsOn(ExecEffAddr) && addr_valid)
+ outs << " A=0x" << hex << addr;
- if (IsOn(ExecFetchSeq) && fetch_seq_valid)
- outs << " FetchSeq=" << dec << fetch_seq;
+ if (IsOn(ExecFetchSeq) && fetch_seq_valid)
+ outs << " FetchSeq=" << dec << fetch_seq;
- if (IsOn(ExecCPSeq) && cp_seq_valid)
- outs << " CPSeq=" << dec << cp_seq;
+ if (IsOn(ExecCPSeq) && cp_seq_valid)
+ outs << " CPSeq=" << dec << cp_seq;
+ }
//
// End of line...
@@ -106,6 +125,29 @@ Trace::ExeTracerRecord::dump()
outs << endl;
}
+void
+Trace::ExeTracerRecord::dump()
+{
+ /*
+ * The behavior this check tries to achieve is that if ExecMacro is on,
+ * the macroop will be printed. If it's on and microops are also on, it's
+ * printed before the microops start printing to give context. If the
+ * microops aren't printed, then it's printed only when the final microop
+ * finishes. Macroops then behave like regular instructions and don't
+ * complete/print when they fault.
+ */
+ if (IsOn(ExecMacro) && staticInst->isMicroop() &&
+ ((IsOn(ExecMicro) &&
+ macroStaticInst && staticInst->isFirstMicroop()) ||
+ (!IsOn(ExecMicro) &&
+ macroStaticInst && staticInst->isLastMicroop()))) {
+ traceInst(macroStaticInst, false);
+ }
+ if (IsOn(ExecMicro) || !staticInst->isMicroop()) {
+ traceInst(staticInst, true);
+ }
+}
+
/* namespace Trace */ }
////////////////////////////////////////////////////////////////////////
diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh
index 84660432b..e49a2bb59 100644
--- a/src/cpu/exetrace.hh
+++ b/src/cpu/exetrace.hh
@@ -47,12 +47,17 @@ class ExeTracerRecord : public InstRecord
{
public:
ExeTracerRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc)
{
}
+ void traceInst(StaticInstPtr inst, bool ran);
+
void dump();
+ virtual void dumpTicks(std::ostream &outs);
};
class ExeTracer : public InstTracer
@@ -64,7 +69,8 @@ class ExeTracer : public InstTracer
InstRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (!IsOn(ExecEnable))
return NULL;
@@ -76,7 +82,7 @@ class ExeTracer : public InstTracer
return NULL;
return new ExeTracerRecord(when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
};
diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py
new file mode 100644
index 000000000..9faadc68c
--- /dev/null
+++ b/src/cpu/inorder/InOrderCPU.py
@@ -0,0 +1,79 @@
+# 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")
+
+ cachePorts = Param.Unsigned(2, "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(64, "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
index 000000000..3453fa675
--- /dev/null
+++ b/src/cpu/inorder/InOrderTrace.py
@@ -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
index 000000000..af237a777
--- /dev/null
+++ b/src/cpu/inorder/SConscript
@@ -0,0 +1,90 @@
+# -*- 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('InOrderStage')
+ TraceFlag('InOrderStall')
+ TraceFlag('InOrderCPU')
+ TraceFlag('RegDepMap')
+ TraceFlag('InOrderDynInst')
+ TraceFlag('Resource')
+ TraceFlag('InOrderAGEN')
+ TraceFlag('InOrderFetchSeq')
+ TraceFlag('InOrderTLB')
+ TraceFlag('InOrderCachePort')
+ TraceFlag('InOrderBPred')
+ TraceFlag('InOrderDecode')
+ TraceFlag('InOrderExecute')
+ TraceFlag('InOrderInstBuffer')
+ TraceFlag('InOrderUseDef')
+ TraceFlag('InOrderMDU')
+ TraceFlag('InOrderGraduation')
+ TraceFlag('RefCount')
+
+ CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
+ 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred',
+ 'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef',
+ 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource'])
+
+ 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/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
index 000000000..82ebd18ea
--- /dev/null
+++ b/src/cpu/inorder/SConsopts
@@ -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
index 000000000..18bb24169
--- /dev/null
+++ b/src/cpu/inorder/comm.hh
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+ InterStageStruct()
+ :size(0), squash(false),
+ branchMispredict(false), branchTaken(false),
+ mispredPC(0), nextPC(0),
+ squashedSeqNum(0), includeSquashInst(false)
+ { }
+
+};
+
+/** 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
index 000000000..70877aae4
--- /dev/null
+++ b/src/cpu/inorder/cpu.cc
@@ -0,0 +1,1253 @@
+/*
+ * 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/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),
+ coreType("default"),
+ _status(Idle),
+ 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);
+
+ // 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");
+ }
+
+
+ for (int i = 0; i < numThreads; ++i) {
+ if (i < params->workload.size()) {
+ DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n",
+ 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];
+ this->thread[i] = new Thread(this, i, dummy_proc, i);
+ }
+
+ // 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 (int stNum=0; stNum < NumStages - 1; stNum++) {
+ stageQueue[stNum] = new StageQueue(NumStages, NumStages);
+ stageQueue[stNum]->id(stNum);
+ }
+
+
+ // 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 - 1)
+ pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]);
+ }
+
+ // 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 = numCycles / 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 / numCycles;
+
+ 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);
+
+ 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.");
+}
+
+
+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::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::wakeCPU()
+{
+ if (/*activityRec.active() || */tickEvent.scheduled()) {
+ DPRINTF(Activity, "CPU already running.\n");
+ return;
+ }
+
+ DPRINTF(Activity, "Waking up CPU\n");
+
+ //@todo: figure out how to count idleCycles correctly
+ //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;
+}
+
+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
index 000000000..adcd28019
--- /dev/null
+++ b/src/cpu/inorder/cpu.hh
@@ -0,0 +1,680 @@
+/*
+ * 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;
+
+ //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 */
+ 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);
+
+ int
+ contextId()
+ {
+ hack_once("return a bogus context id");
+ return 0;
+ }
+
+ /** 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();*/ }
+
+ /** 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;
+ }
+
+ /** Get & Update Next Event Number */
+ 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 = 0);
+
+ /** Reads a misc. register, including any side effects the read
+ * might have as defined by the architecture.
+ */
+ MiscReg readMiscReg(int misc_reg, unsigned tid = 0);
+
+ /** Sets a miscellaneous register. */
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0);
+
+ /** 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 = 0);
+
+ /** 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);
+
+ /** 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();
+
+ /** 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);
+
+ 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;
+
+ /** 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;
+
+ 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; }
+
+ /** 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
index 000000000..5e389b256
--- /dev/null
+++ b/src/cpu/inorder/first_stage.cc
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include "base/str.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+#include "params/InOrderTrace.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+FirstStage::FirstStage(Params *params, unsigned stage_num)
+ : PipelineStage(params, stage_num), numFetchingThreads(1),
+ fetchPolicy(FirstStage::RoundRobin)
+{
+ for(int tid=0; tid < this->numThreads; tid++) {
+ stageStatus[tid] = Running;
+ }
+}
+
+void
+FirstStage::setCPU(InOrderCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ fetchPriorityList = &cpu->fetchPriorityList;
+
+ DPRINTF(InOrderStage, "Set CPU pointer.\n");
+}
+
+
+void
+FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+ // Set status to squashing.
+ //stageStatus[tid] = Squashing;
+
+ // Clear the instruction list and skid buffer in case they have any
+ // insts in them.
+ DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n");
+ while (!insts[tid].empty()) {
+ if (insts[tid].front()->seqNum <= squash_seq_num) {
+ DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= "
+ "squashing seqNum %i.\n",
+ tid,
+ insts[tid].front()->seqNum,
+ squash_seq_num);
+
+ DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming "
+ "instructions before delay slot [sn:%i]. %i insts"
+ "left.\n", tid, squash_seq_num,
+ insts[tid].size());
+ break;
+ }
+ DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
+ tid, insts[tid].front()->seqNum, insts[tid].front()->PC);
+ insts[tid].pop();
+ }
+
+ // Now that squash has propagated to the first stage,
+ // Alert CPU to remove instructions from the CPU instruction list.
+ // @todo: Move this to the CPU object.
+ cpu->removeInstsUntil(squash_seq_num, tid);
+}
+
+void
+FirstStage::processStage(bool &status_change)
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ //Check stall and squash signals.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+ status_change = checkSignalsAndUpdate(tid) || status_change;
+ }
+
+ for (int threadFetched = 0; threadFetched < numFetchingThreads;
+ threadFetched++) {
+ int tid = getFetchingThread(fetchPolicy);
+
+ if (tid >= 0) {
+ DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
+ processThread(status_change, tid);
+ } else {
+ DPRINTF(InOrderStage, "No more threads to fetch from.\n");
+ }
+ }
+}
+
+//@TODO: Note in documentation, that when you make a pipeline stage change, then
+//make sure you change the first stage too
+void
+FirstStage::processInsts(unsigned tid)
+{
+ bool all_reqs_completed = true;
+
+ for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) {
+ DynInstPtr inst;
+ bool new_inst = false;
+
+ if (!insts[tid].empty()) {
+ inst = insts[tid].front();
+ } else {
+ // Get new instruction.
+ new_inst = true;
+
+ inst = new InOrderDynInst(cpu,
+ cpu->thread[tid],
+ cpu->nextInstSeqNum(tid),
+ tid);
+
+#if TRACING_ON
+ inst->traceData =
+ tracer->getInstRecord(ThePipeline::NumStages,
+ cpu->stageTracing,
+ cpu->thread[tid]->getTC());
+
+#endif // TRACING_ON
+
+ DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n",
+ inst->readTid(),
+ inst->seqNum,
+ 0/*inst->curCount()*/);
+
+ // Add instruction to the CPU's list of instructions.
+ inst->setInstListIt(cpu->addInst(inst));
+
+ DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n",
+ inst->readTid(),
+ inst->seqNum,
+ 0/*inst->curCount()*/);
+
+ // Create Front-End Resource Schedule For Instruction
+ ThePipeline::createFrontEndSchedule(inst);
+ }
+
+ // Don't let instruction pass to next stage if it hasnt completed
+ // all of it's requests for this stage.
+ all_reqs_completed = processInstSchedule(inst);
+
+ if (!all_reqs_completed) {
+ if (new_inst) {
+ DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all "
+ "requests for this stage. Keep in stage inst. "
+ "list.\n", tid, inst->seqNum);
+ insts[tid].push(inst);
+ }
+ break;
+ } else if (!insts[tid].empty()){
+ insts[tid].pop();
+ }
+
+ sendInstToNextStage(inst);
+ //++stageProcessedInsts;
+ }
+
+ // Record that stage has written to the time buffer for activity
+ // tracking.
+ if (toNextStageIndex) {
+ wroteToTimeBuffer = true;
+ }
+}
+
+int
+FirstStage::getFetchingThread(FetchPriority &fetch_priority)
+{
+ if (numThreads > 1) {
+ switch (fetch_priority) {
+
+ case SingleThread:
+ return 0;
+
+ case RoundRobin:
+ return roundRobin();
+
+ default:
+ return -1;
+ }
+ } else {
+ int tid = *((*activeThreads).begin());
+
+ if (stageStatus[tid] == Running ||
+ stageStatus[tid] == Idle) {
+ return tid;
+ } else {
+ return -1;
+ }
+ }
+
+}
+
+int
+FirstStage::roundRobin()
+{
+ list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin();
+ list<unsigned>::iterator end = (*fetchPriorityList).end();
+
+ int high_pri;
+
+ while (pri_iter != end) {
+ high_pri = *pri_iter;
+
+ assert(high_pri <= numThreads);
+
+ if (stageStatus[high_pri] == Running ||
+ stageStatus[high_pri] == Idle) {
+
+ (*fetchPriorityList).erase(pri_iter);
+ (*fetchPriorityList).push_back(high_pri);
+
+ return high_pri;
+ }
+
+ pri_iter++;
+ }
+
+ return -1;
+}
diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh
new file mode 100644
index 000000000..55914c85c
--- /dev/null
+++ b/src/cpu/inorder/first_stage.hh
@@ -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/o3/mips/thread_context.cc b/src/cpu/inorder/inorder_cpu_builder.cc
index 0061a2a63..0088a3bd9 100755..100644
--- a/src/cpu/o3/mips/thread_context.cc
+++ b/src/cpu/inorder/inorder_cpu_builder.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,12 +25,36 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-#include "cpu/o3/thread_context.hh"
-#include "cpu/o3/thread_context_impl.hh"
+#include <string>
+
+#include "cpu/base.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/cpu.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);
+}
+
-template class O3ThreadContext<MipsSimpleImpl>;
diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc
new file mode 100644
index 000000000..ceb3cbe51
--- /dev/null
+++ b/src/cpu/inorder/inorder_dyn_inst.cc
@@ -0,0 +1,724 @@
+/*
+ * 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)
+ : seqNum(0), staticInst(_staticInst), traceData(NULL)
+{
+ initVars();
+}
+
+InOrderDynInst::InOrderDynInst()
+ : seqNum(0), 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);
+}
+
+
+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);
+}
+
+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)
+{
+ panic("Prefetch Unimplemented\n");
+}
+
+void
+InOrderDynInst::writeHint(Addr addr, int size, unsigned flags)
+{
+ panic("Write-Hint Unimplemented\n");
+}
+
+/**
+ * @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)
+{
+ int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
+ return cpu->readMiscRegNoEffect(reg, 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)
+{
+ int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
+ return this->cpu->readMiscReg(reg, 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
diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh
new file mode 100644
index 000000000..55c61ffb9
--- /dev/null
+++ b/src/cpu/inorder/inorder_dyn_inst.hh
@@ -0,0 +1,971 @@
+/*
+ * 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;
+
+ /** 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
index 000000000..f12a1b7a9
--- /dev/null
+++ b/src/cpu/inorder/inorder_trace.cc
@@ -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
index 000000000..4338b438c
--- /dev/null
+++ b/src/cpu/inorder/inorder_trace.hh
@@ -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/o3/params.hh b/src/cpu/inorder/params.hh
index b487778c6..51b7409ad 100755..100644
--- a/src/cpu/o3/params.hh
+++ b/src/cpu/inorder/params.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * 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
@@ -25,101 +25,45 @@
* (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
+ * Authors: Korey Sewell
*/
-#ifndef __CPU_O3_PARAMS_HH__
-#define __CPU_O3_PARAMS_HH__
+#ifndef __CPU_INORDER_PARAMS_HH__
+#define __CPU_INORDER_PARAMS_HH__
-#include "cpu/o3/cpu.hh"
+#include "cpu/base.hh"
//Forward declarations
-class FUPool;
+class FunctionalMemory;
+class Process;
+class MemObject;
+class MemInterface;
/**
- * This file defines the parameters that will be used for the O3CPU.
+ * 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 O3Params : public BaseO3CPU::Params
+
+class InOrderParams : public BaseCPU::Params
{
public:
- unsigned activity;
- //
- // Pointers to key objects
- //
+ // Workloads
#if !FULL_SYSTEM
std::vector<Process *> workload;
Process *process;
#endif // FULL_SYSTEM
- BaseCPU *checker;
-
//
- // Caches
+ // Memory System/Caches
//
- // MemInterface *icacheInterface;
- // MemInterface *dcacheInterface;
-
unsigned cachePorts;
+ std::string fetchMemPort;
+ std::string dataMemPort;
//
- // Fetch
- //
- unsigned decodeToFetchDelay;
- unsigned renameToFetchDelay;
- unsigned iewToFetchDelay;
- unsigned commitToFetchDelay;
- unsigned fetchWidth;
-
- //
- // Decode
- //
- unsigned renameToDecodeDelay;
- unsigned iewToDecodeDelay;
- unsigned commitToDecodeDelay;
- unsigned fetchToDecodeDelay;
- unsigned decodeWidth;
-
- //
- // Rename
- //
- unsigned iewToRenameDelay;
- unsigned commitToRenameDelay;
- unsigned decodeToRenameDelay;
- unsigned renameWidth;
-
- //
- // IEW
- //
- unsigned commitToIEWDelay;
- unsigned renameToIEWDelay;
- unsigned issueToExecuteDelay;
- unsigned dispatchWidth;
- unsigned issueWidth;
- unsigned wbWidth;
- unsigned wbDepth;
- FUPool *fuPool;
-
- //
- // Commit
- //
- unsigned iewToCommitDelay;
- unsigned renameToROBDelay;
- unsigned commitWidth;
- unsigned squashWidth;
- Tick trapLatency;
- Tick fetchTrapLatency;
-
- //
- // Timebuffer sizes
- //
- unsigned backComSize;
- unsigned forwardComSize;
-
- //
- // Branch predictor (BP, BTB, RAS)
+ // Branch predictor (BP & BTB)
//
std::string predType;
unsigned localPredictorSize;
@@ -131,50 +75,50 @@ class O3Params : public BaseO3CPU::Params
unsigned globalHistoryBits;
unsigned choicePredictorSize;
unsigned choiceCtrBits;
-
unsigned BTBEntries;
unsigned BTBTagSize;
-
unsigned RASSize;
- //
- // Load store queue
- //
- unsigned LQEntries;
- unsigned SQEntries;
+ // Pipeline Parameters
+ unsigned stageWidth;
+
+ // InOrderCPU Simulation Parameters
+ unsigned instShiftAmt;
+ unsigned activity;
+ unsigned deferRegistration;
//
- // Memory dependence
+ // Memory Parameters
//
- unsigned SSITSize;
- unsigned LFSTSize;
+ unsigned memBlockSize;
//
- // Miscellaneous
+ // Multiply Divide Unit
//
- unsigned numPhysIntRegs;
- unsigned numPhysFloatRegs;
- unsigned numIQEntries;
- unsigned numROBEntries;
+ // @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;
- //SMT Parameters
- unsigned smtNumFetchingThreads;
+ /** Latency & Repeat Rate for 8-bit Divide Insts */
+ unsigned div8Latency;
+ unsigned div8RepeatRate;
- std::string smtFetchPolicy;
+ /** Latency & Repeat Rate for 16-bit Divide Insts */
+ unsigned div16Latency;
+ unsigned div16RepeatRate;
- std::string smtIQPolicy;
- unsigned smtIQThreshold;
+ /** Latency & Repeat Rate for 24-bit Divide Insts */
+ unsigned div24Latency;
+ unsigned div24RepeatRate;
- std::string smtLSQPolicy;
- unsigned smtLSQThreshold;
+ /** Latency & Repeat Rate for 32-bit Divide Insts */
+ unsigned div32Latency;
+ unsigned div32RepeatRate;
- std::string smtCommitPolicy;
- std::string smtROBPolicy;
- unsigned smtROBThreshold;
-
- // Probably can get this from somewhere.
- unsigned instShiftAmt;
};
-#endif // __CPU_O3_ALPHA_PARAMS_HH__
+#endif // _CPU_INORDER_PARAMS_HH__
diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc
new file mode 100644
index 000000000..cb69464b0
--- /dev/null
+++ b/src/cpu/inorder/pipeline_stage.cc
@@ -0,0 +1,1021 @@
+/*
+ * 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)
+ : stageNum(stage_num), stageWidth(ThePipeline::StageWidth),
+ numThreads(ThePipeline::MaxThreads), _status(Inactive),
+ stageBufferMax(ThePipeline::interStageBuffSize[stage_num]),
+ prevStageValid(false), nextStageValid(false)
+{
+ init(params);
+}
+
+void
+PipelineStage::init(Params *params)
+{
+ 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;
+ }
+}
+
+
+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);
+ nextStage->size = 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.
+ panic("Switching Out of Stages Unimplemented");
+}
+
+
+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 (nextStageValid && stalls[tid].stage[stageNum + 1]) {
+ DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n",
+ tid, stageNum + 1);
+ ret_val = true;
+ }
+
+ if (!stalls[tid].resources.empty()) {
+ 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]->prevStage->size :
+ 0;
+
+ int avail = stageBufferMax - total -0;// incoming_insts;
+
+ if (avail < 0)
+ fatal("stageNum %i:stageBufferAvail() < 0...stBMax=%i,total=%i,incoming=%i=>%i",
+ stageNum, stageBufferMax, total, incoming_insts, avail);
+
+ return avail;
+}
+
+bool
+PipelineStage::canSendInstToStage(unsigned stage_num)
+{
+ bool buffer_avail = false;
+
+ if (cpu->pipelineStage[stage_num]->prevStageValid) {
+ buffer_avail = cpu->pipelineStage[stage_num]->stageBufferAvail() >= 1;
+ }
+
+ if (!buffer_avail && nextStageQueueValid(stage_num)) {
+ 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);
+ }
+}
+
+
+int
+PipelineStage::skidSize()
+{
+ int total = 0;
+
+ for (int i=0; i < ThePipeline::MaxThreads; i++) {
+ total += skidBuffer[i].size();
+ }
+
+ return total;
+}
+
+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 stage buffer %i.\n",
+ insts_from_prev_stage, prevStageQueue->id());
+
+ 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;
+
+ if (nextStageValid)
+ nextStage->size = 0;
+
+ toNextStageIndex = 0;
+
+ sortInsts();
+
+ processStage(status_change);
+
+ if (status_change) {
+ updateStatus();
+ }
+
+ if (wroteToTimeBuffer) {
+ DPRINTF(Activity, "Activity this cycle.\n");
+ cpu->activityThisCycle();
+ }
+
+ DPRINTF(InOrderStage, "\n\n");
+}
+
+void
+PipelineStage::setResStall(ResReqPtr res_req, 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 left in stage %i incoming buffer.\n", skidSize(),
+ stageNum);
+
+ DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", stageBufferAvail(),
+ stageNum);
+}
+
+void
+PipelineStage::processThread(bool &status_change, 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;
+
+ while (insts_available > 0 &&
+ insts_processed < stageWidth &&
+ (!nextStageValid || canSendInstToStage(stageNum+1)) &&
+ last_req_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);
+
+ // Don't let instruction pass to next stage if it hasnt completed
+ // all of it's requests for this stage.
+ if (!last_req_completed)
+ continue;
+
+ // Send to Next Stage or Break Loop
+ if (nextStageValid && !sendInstToNextStage(inst)) {
+ DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage %i.\n",
+ tid, inst->seqNum,inst->nextStage);
+ break;
+ }
+
+ insts_processed++;
+
+ insts_to_stage.pop();
+
+ //++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.
+ 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
+ // NOTE: Some Resources will update this nextStage var. to
+ // for bypassing, so can't always assume nextStage=stageNum+1
+ if (inst->nextStage == stageNum)
+ inst->nextStage++;
+
+ bool success = false;
+ int tid = inst->readTid();
+ int next_stage = inst->nextStage;
+ int prev_stage = next_stage - 1;
+
+ assert(next_stage >= 1);
+ assert(prev_stage >= 0);
+
+ DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to stage %u.\n", tid,
+ stageNum+1);
+
+ if (!canSendInstToStage(inst->nextStage)) {
+ DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to stage %u.\n", tid,
+ stageNum+1);
+ return false;
+ }
+
+
+ if (nextStageQueueValid(inst->nextStage - 1)) {
+ if (inst->seqNum > cpu->squashSeqNum[tid] &&
+ curTick == cpu->lastSquashCycle[tid]) {
+ DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion "
+ "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage);
+ } else {
+ if (nextStageValid) {
+ DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n",
+ tid, cpu->pipelineStage[next_stage]->stageBufferAvail());
+ }
+
+ DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into "
+ "index %i of stage buffer %i queue.\n",
+ tid, inst->seqNum, toNextStageIndex,
+ cpu->pipelineStage[prev_stage]->nextStageQueue->id());
+
+ 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()
+{
+ cprintf("Insts in Stage %i skidbuffers\n",stageNum);
+
+ 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
index 000000000..b074639fb
--- /dev/null
+++ b/src/cpu/inorder/pipeline_stage.hh
@@ -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);
+
+ /** 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();
+
+ /** 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 canSendInstToStage(unsigned stage_num);
+
+ /** 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);
+
+ /** Total size of all skid buffers */
+ int skidSize();
+
+ /** 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
index 000000000..50c30af1e
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.5stage.cc
@@ -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
index 000000000..aea6eff37
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.5stage.hh
@@ -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
index 000000000..d686bb3bc
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.cc
@@ -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
index 000000000..91e537366
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.hh
@@ -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
index 000000000..9d2ed8e61
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
@@ -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
index 000000000..22da4ea0f
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
@@ -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
index 000000000..eb899452a
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.cc
@@ -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
index 000000000..3c49143bc
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.hh
@@ -0,0 +1,170 @@
+/*
+ * 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 "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->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
index 000000000..a405b1fb9
--- /dev/null
+++ b/src/cpu/inorder/reg_dep_map.cc
@@ -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
index 000000000..ba2a8c8a3
--- /dev/null
+++ b/src/cpu/inorder/reg_dep_map.hh
@@ -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
index 000000000..3106628f0
--- /dev/null
+++ b/src/cpu/inorder/resource.cc
@@ -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
index 000000000..b857e59ed
--- /dev/null
+++ b/src/cpu/inorder/resource.hh
@@ -0,0 +1,401 @@
+/*
+ * 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();
+
+ /** 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
index 000000000..4a0258e71
--- /dev/null
+++ b/src/cpu/inorder/resource_pool.9stage.cc
@@ -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
index 000000000..94af68c7a
--- /dev/null
+++ b/src/cpu/inorder/resource_pool.cc
@@ -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
index 000000000..35fce7db7
--- /dev/null
+++ b/src/cpu/inorder/resource_pool.hh
@@ -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
index 000000000..f462b12ea
--- /dev/null
+++ b/src/cpu/inorder/resources/agen_unit.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include "cpu/inorder/resources/agen_unit.hh"
+
+AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+AGENUnit::execute(int slot_num)
+{
+ ResourceRequest* agen_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid;
+ int seq_num = inst->seqNum;
+
+ tid = inst->readTid();
+ agen_req->fault = NoFault;
+
+ switch (agen_req->cmd)
+ {
+ case GenerateAddr:
+ {
+ // Load/Store Instruction
+ if (inst->isMemRef()) {
+ DPRINTF(InOrderAGEN, "[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(InOrderAGEN, "[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(InOrderAGEN, "[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(InOrderAGEN, "[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/o3/mips/params.hh b/src/cpu/inorder/resources/agen_unit.hh
index 2688d3fb3..2010c9fa6 100644
--- a/src/cpu/o3/mips/params.hh
+++ b/src/cpu/inorder/resources/agen_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,40 +25,40 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __CPU_O3_MIPS_PARAMS_HH__
-#define __CPU_O3_MIPS_PARAMS_HH__
+#ifndef __CPU_INORDER_AGEN_UNIT_HH__
+#define __CPU_INORDER_AGEN_UNIT_HH__
-#include "cpu/o3/cpu.hh"
-#include "cpu/o3/params.hh"
+#include <vector>
+#include <list>
+#include <string>
-//Forward declarations
-namespace MipsISA
-{
- class MipsDTB;
- class MipsITB;
-}
-class MemObject;
-class Process;
-class System;
+#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"
-/**
- * This file defines the parameters that will be used for the MipsO3CPU.
- * 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 AGENUnit : public Resource {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
-class MipsSimpleParams : public O3Params
-{
public:
- MipsSimpleParams() {}
+ 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);
- //Full System Paramater Objects place here
- MipsISA::ITB *itb;
- MipsISA::DTB *dtb;
+ protected:
+ /** @todo: Add Resource Stats Here */
};
-#endif // __CPU_O3_MIPS_PARAMS_HH__
+#endif //__CPU_INORDER_DECODE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/bpred_unit.cc b/src/cpu/inorder/resources/bpred_unit.cc
new file mode 100644
index 000000000..66d0779a2
--- /dev/null
+++ b/src/cpu/inorder/resources/bpred_unit.cc
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Kevin Lim
+ */
+
+#include <list>
+#include <vector>
+
+#include "base/trace.hh"
+#include "base/traceflags.hh"
+#include "cpu/inorder/resources/bpred_unit.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+BPredUnit::BPredUnit(ThePipeline::Params *params)
+ : BTB(params->BTBEntries,
+ params->BTBTagSize,
+ params->instShiftAmt)
+{
+ // Setup the selected predictor.
+ if (params->predType == "local") {
+ localBP = new LocalBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->instShiftAmt);
+ predictor = Local;
+ } else if (params->predType == "tournament") {
+ tournamentBP = new TournamentBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->localHistoryTableSize,
+ params->localHistoryBits,
+ params->globalPredictorSize,
+ params->globalHistoryBits,
+ params->globalCtrBits,
+ params->choicePredictorSize,
+ params->choiceCtrBits,
+ params->instShiftAmt);
+ predictor = Tournament;
+ } else {
+ fatal("Invalid BP selected!");
+ }
+
+ for (int i=0; i < ThePipeline::MaxThreads; i++)
+ RAS[i].init(params->RASSize);
+}
+
+
+void
+BPredUnit::regStats()
+{
+ lookups
+ .name(name() + ".BPredUnit.lookups")
+ .desc("Number of BP lookups")
+ ;
+
+ condPredicted
+ .name(name() + ".BPredUnit.condPredicted")
+ .desc("Number of conditional branches predicted")
+ ;
+
+ condIncorrect
+ .name(name() + ".BPredUnit.condIncorrect")
+ .desc("Number of conditional branches incorrect")
+ ;
+
+ BTBLookups
+ .name(name() + ".BPredUnit.BTBLookups")
+ .desc("Number of BTB lookups")
+ ;
+
+ BTBHits
+ .name(name() + ".BPredUnit.BTBHits")
+ .desc("Number of BTB hits")
+ ;
+
+ BTBCorrect
+ .name(name() + ".BPredUnit.BTBCorrect")
+ .desc("Number of correct BTB predictions (this stat may not "
+ "work properly.")
+ ;
+
+ usedRAS
+ .name(name() + ".BPredUnit.usedRAS")
+ .desc("Number of times the RAS was used to get a target.")
+ ;
+
+ RASIncorrect
+ .name(name() + ".BPredUnit.RASInCorrect")
+ .desc("Number of incorrect RAS predictions.")
+ ;
+}
+
+
+void
+BPredUnit::switchOut()
+{
+ // Clear any state upon switch out.
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
+ squash(0, i);
+ }
+}
+
+
+void
+BPredUnit::takeOverFrom()
+{
+ // Can reset all predictor state, but it's not necessarily better
+ // than leaving it be.
+/*
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i)
+ RAS[i].reset();
+
+ BP.reset();
+ BTB.reset();
+*/
+}
+
+
+bool
+BPredUnit::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
+{
+ // See if branch predictor predicts taken.
+ // If so, get its target addr either from the BTB or the RAS.
+ // Save off record of branch stuff so the RAS can be fixed
+ // up once it's done.
+
+ using TheISA::MachInst;
+
+ bool pred_taken = false;
+ Addr target;
+
+ ++lookups;
+
+ void *bp_history = NULL;
+
+ if (inst->isUncondCtrl()) {
+ DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid);
+ pred_taken = true;
+ // Tell the BP there was an unconditional branch.
+ BPUncond(bp_history);
+
+ if (inst->isReturn() && RAS[tid].empty()) {
+ DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting "
+ "false.\n", tid);
+ pred_taken = false;
+ }
+ } else {
+ ++condPredicted;
+
+ pred_taken = BPLookup(PC, bp_history);
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i "
+ "for PC %#x\n",
+ tid, pred_taken, inst->readPC());
+ }
+
+ PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
+ bp_history, tid);
+
+ // Now lookup in the BTB or RAS.
+ if (pred_taken) {
+ if (inst->isReturn()) {
+ ++usedRAS;
+
+ // If it's a function return call, then look up the address
+ // in the RAS.
+ target = RAS[tid].top();
+
+ // Record the top entry of the RAS, and its index.
+ predict_record.usedRAS = true;
+ predict_record.RASIndex = RAS[tid].topIdx();
+ predict_record.RASTarget = target;
+
+ assert(predict_record.RASIndex < 16);
+
+ RAS[tid].pop();
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, "
+ "RAS predicted target: %#x, RAS index: %i.\n",
+ tid, inst->readPC(), target, predict_record.RASIndex);
+ } else {
+ ++BTBLookups;
+
+ if (inst->isCall()) {
+ RAS[tid].push(PC + sizeof(MachInst));
+
+ // Record that it was a call so that the top RAS entry can
+ // be popped off if the speculation is incorrect.
+ predict_record.wasCall = true;
+
+ DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call"
+ ", adding %#x to the RAS.\n",
+ tid, inst->readPC(), PC + sizeof(MachInst));
+ }
+
+ if (inst->isCall() &&
+ inst->isUncondCtrl() &&
+ inst->isDirectCtrl()) {
+ target = inst->branchTarget();
+
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted"
+ " target to %#x.\n",
+ tid, inst->readPC(), target);
+ } else if (BTB.valid(PC, tid)) {
+ ++BTBHits;
+
+ // If it's not a return, use the BTB to get the target addr.
+ target = BTB.lookup(PC, tid);
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted"
+ " target is %#x.\n",
+ tid, inst->readPC(), target);
+ } else {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a "
+ "valid entry.\n",tid);
+ pred_taken = false;
+ }
+ }
+ }
+
+ if (pred_taken) {
+ // Set the PC and the instruction's predicted target.
+ PC = target;
+ inst->setPredTarg(target);
+ } else {
+ PC = PC + sizeof(MachInst);
+ inst->setPredTarg(PC);
+ }
+
+ predHist[tid].push_front(predict_record);
+
+ DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size());
+
+ inst->setBranchPred(pred_taken);
+
+ return pred_taken;
+}
+
+
+void
+BPredUnit::update(const InstSeqNum &done_sn, unsigned tid)
+{
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Commiting branches until sequence"
+ "number %lli.\n", tid, done_sn);
+
+ while (!predHist[tid].empty() &&
+ predHist[tid].back().seqNum <= done_sn) {
+ // Update the branch predictor with the correct results.
+ BPUpdate(predHist[tid].back().PC,
+ predHist[tid].back().predTaken,
+ predHist[tid].back().bpHistory);
+
+ predHist[tid].pop_back();
+ }
+}
+
+
+void
+BPredUnit::squash(const InstSeqNum &squashed_sn, unsigned tid)
+{
+ History &pred_hist = predHist[tid];
+
+ while (!pred_hist.empty() &&
+ pred_hist.front().seqNum > squashed_sn) {
+ if (pred_hist.front().usedRAS) {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
+ " target: %#x.\n",
+ tid,
+ pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ RAS[tid].restore(pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ } else if (pred_hist.front().wasCall) {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry "
+ "added to the RAS.\n",tid);
+
+ RAS[tid].pop();
+ }
+
+ // This call should delete the bpHistory.
+ BPSquash(pred_hist.front().bpHistory);
+
+ pred_hist.pop_front();
+ }
+
+}
+
+
+void
+BPredUnit::squash(const InstSeqNum &squashed_sn,
+ const Addr &corr_target,
+ const bool actually_taken,
+ unsigned tid)
+{
+ // Now that we know that a branch was mispredicted, we need to undo
+ // all the branches that have been seen up until this branch and
+ // fix up everything.
+
+ History &pred_hist = predHist[tid];
+
+ ++condIncorrect;
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
+ "setting target to %#x.\n",
+ tid, squashed_sn, corr_target);
+
+ squash(squashed_sn, tid);
+
+ // If there's a squash due to a syscall, there may not be an entry
+ // corresponding to the squash. In that case, don't bother trying to
+ // fix up the entry.
+ if (!pred_hist.empty()) {
+ assert(pred_hist.front().seqNum == squashed_sn);
+ if (pred_hist.front().usedRAS) {
+ ++RASIncorrect;
+ }
+
+ BPUpdate(pred_hist.front().PC, actually_taken,
+ pred_hist.front().bpHistory);
+
+ BTB.update(pred_hist.front().PC, corr_target, tid);
+ pred_hist.pop_front();
+ }
+}
+
+
+void
+BPredUnit::BPUncond(void * &bp_history)
+{
+ // Only the tournament predictor cares about unconditional branches.
+ if (predictor == Tournament) {
+ tournamentBP->uncondBr(bp_history);
+ }
+}
+
+
+void
+BPredUnit::BPSquash(void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->squash(bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->squash(bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+bool
+BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history)
+{
+ if (predictor == Local) {
+ return localBP->lookup(inst_PC, bp_history);
+ } else if (predictor == Tournament) {
+ return tournamentBP->lookup(inst_PC, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+void
+BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->update(inst_PC, taken, bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->update(inst_PC, taken, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+void
+BPredUnit::dump()
+{
+ /*typename History::iterator pred_hist_it;
+
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
+ if (!predHist[i].empty()) {
+ pred_hist_it = predHist[i].begin();
+
+ cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
+
+ while (pred_hist_it != predHist[i].end()) {
+ cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
+ "bpHistory:%#x\n",
+ (*pred_hist_it).seqNum, (*pred_hist_it).PC,
+ (*pred_hist_it).tid, (*pred_hist_it).predTaken,
+ (*pred_hist_it).bpHistory);
+ pred_hist_it++;
+ }
+
+ cprintf("\n");
+ }
+ }*/
+}
diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh
new file mode 100644
index 000000000..bd68459d1
--- /dev/null
+++ b/src/cpu/inorder/resources/bpred_unit.hh
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Kevin Lim
+ * Korey Sewell
+ */
+
+#ifndef __CPU_INORDER_BPRED_UNIT_HH__
+#define __CPU_INORDER_BPRED_UNIT_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "cpu/inst_seq.hh"
+
+//#include "cpu/inorder/params.hh"
+#include "cpu/o3/2bit_local_pred.hh"
+#include "cpu/o3/btb.hh"
+#include "cpu/o3/ras.hh"
+#include "cpu/o3/tournament_pred.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+#include <list>
+
+/**
+ * Basically a wrapper class to hold both the branch predictor
+ * and the BTB.
+ */
+class BPredUnit
+{
+ private:
+
+ enum PredType {
+ Local,
+ Tournament
+ };
+
+ PredType predictor;
+
+ public:
+
+ /**
+ * @param params The params object, that has the size of the BP and BTB.
+ */
+ BPredUnit(ThePipeline::Params *params);
+
+ /**
+ * Registers statistics.
+ */
+ void regStats();
+
+ void switchOut();
+
+ void takeOverFrom();
+
+ /**
+ * Predicts whether or not the instruction is a taken branch, and the
+ * target of the branch if it is taken.
+ * @param inst The branch instruction.
+ * @param PC The predicted PC is passed back through this parameter.
+ * @param tid The thread id.
+ * @return Returns if the branch is taken or not.
+ */
+ bool predict(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid);
+
+ // @todo: Rename this function.
+ void BPUncond(void * &bp_history);
+
+ /**
+ * Tells the branch predictor to commit any updates until the given
+ * sequence number.
+ * @param done_sn The sequence number to commit any older updates up until.
+ * @param tid The thread id.
+ */
+ void update(const InstSeqNum &done_sn, unsigned tid);
+
+ /**
+ * Squashes all outstanding updates until a given sequence number.
+ * @param squashed_sn The sequence number to squash any younger updates up
+ * until.
+ * @param tid The thread id.
+ */
+ void squash(const InstSeqNum &squashed_sn, unsigned tid);
+
+ /**
+ * Squashes all outstanding updates until a given sequence number, and
+ * corrects that sn's update with the proper address and taken/not taken.
+ * @param squashed_sn The sequence number to squash any younger updates up
+ * until.
+ * @param corr_target The correct branch target.
+ * @param actually_taken The correct branch direction.
+ * @param tid The thread id.
+ */
+ void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
+ bool actually_taken, unsigned tid);
+
+ /**
+ * @param bp_history Pointer to the history object. The predictor
+ * will need to update any state and delete the object.
+ */
+ void BPSquash(void *bp_history);
+
+ /**
+ * Looks up a given PC in the BP to see if it is taken or not taken.
+ * @param inst_PC The PC to look up.
+ * @param bp_history Pointer that will be set to an object that
+ * has the branch predictor state associated with the lookup.
+ * @return Whether the branch is taken or not taken.
+ */
+ bool BPLookup(Addr &inst_PC, void * &bp_history);
+
+ /**
+ * Looks up a given PC in the BTB to see if a matching entry exists.
+ * @param inst_PC The PC to look up.
+ * @return Whether the BTB contains the given PC.
+ */
+ bool BTBValid(Addr &inst_PC)
+ { return BTB.valid(inst_PC, 0); }
+
+ /**
+ * Looks up a given PC in the BTB to get the predicted target.
+ * @param inst_PC The PC to look up.
+ * @return The address of the target of the branch.
+ */
+ Addr BTBLookup(Addr &inst_PC)
+ { return BTB.lookup(inst_PC, 0); }
+
+ /**
+ * Updates the BP with taken/not taken information.
+ * @param inst_PC The branch's PC that will be updated.
+ * @param taken Whether the branch was taken or not taken.
+ * @param bp_history Pointer to the branch predictor state that is
+ * associated with the branch lookup that is being updated.
+ * @todo Make this update flexible enough to handle a global predictor.
+ */
+ void BPUpdate(Addr &inst_PC, bool taken, void *bp_history);
+
+ /**
+ * Updates the BTB with the target of a branch.
+ * @param inst_PC The branch's PC that will be updated.
+ * @param target_PC The branch's target that will be added to the BTB.
+ */
+ void BTBUpdate(Addr &inst_PC, Addr &target_PC)
+ { BTB.update(inst_PC, target_PC,0); }
+
+ void dump();
+
+ private:
+ struct PredictorHistory {
+ /**
+ * Makes a predictor history struct that contains any
+ * information needed to update the predictor, BTB, and RAS.
+ */
+ PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
+ const bool pred_taken, void *bp_history,
+ const unsigned _tid)
+ : seqNum(seq_num), PC(inst_PC), RASTarget(0),
+ RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0),
+ wasCall(0), bpHistory(bp_history)
+ { }
+
+ /** The sequence number for the predictor history entry. */
+ InstSeqNum seqNum;
+
+ /** The PC associated with the sequence number. */
+ Addr PC;
+
+ /** The RAS target (only valid if a return). */
+ Addr RASTarget;
+
+ /** The RAS index of the instruction (only valid if a call). */
+ unsigned RASIndex;
+
+ /** The thread id. */
+ unsigned tid;
+
+ /** Whether or not it was predicted taken. */
+ bool predTaken;
+
+ /** Whether or not the RAS was used. */
+ bool usedRAS;
+
+ /** Whether or not the instruction was a call. */
+ bool wasCall;
+
+ /** Pointer to the history object passed back from the branch
+ * predictor. It is used to update or restore state of the
+ * branch predictor.
+ */
+ void *bpHistory;
+ };
+
+ typedef std::list<PredictorHistory> History;
+
+ /**
+ * The per-thread predictor history. This is used to update the predictor
+ * as instructions are committed, or restore it to the proper state after
+ * a squash.
+ */
+ History predHist[ThePipeline::MaxThreads];
+
+ /** The local branch predictor. */
+ LocalBP *localBP;
+
+ /** The tournament branch predictor. */
+ TournamentBP *tournamentBP;
+
+ /** The BTB. */
+ DefaultBTB BTB;
+
+ /** The per-thread return address stack. */
+ ReturnAddrStack RAS[ThePipeline::MaxThreads];
+
+ /** Stat for number of BP lookups. */
+ Stats::Scalar lookups;
+ /** Stat for number of conditional branches predicted. */
+ Stats::Scalar condPredicted;
+ /** Stat for number of conditional branches predicted incorrectly. */
+ Stats::Scalar condIncorrect;
+ /** Stat for number of BTB lookups. */
+ Stats::Scalar BTBLookups;
+ /** Stat for number of BTB hits. */
+ Stats::Scalar BTBHits;
+ /** Stat for number of times the BTB is correct. */
+ Stats::Scalar BTBCorrect;
+ /** Stat for number of times the RAS is used to get a target. */
+ Stats::Scalar usedRAS;
+ /** Stat for number of times the RAS is incorrect. */
+ Stats::Scalar RASIncorrect;
+};
+
+#endif // __CPU_INORDER_BPRED_UNIT_HH__
diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc
new file mode 100644
index 000000000..511a0ac82
--- /dev/null
+++ b/src/cpu/inorder/resources/branch_predictor.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include "cpu/inorder/resources/branch_predictor.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ branchPred(params)
+{
+ instSize = sizeof(MachInst);
+}
+
+void
+BranchPredictor::regStats()
+{
+ predictedTaken
+ .name(name() + ".predictedTaken")
+ .desc("Number of Branches Predicted As Taken (True).");
+
+ predictedNotTaken
+ .name(name() + ".predictedNotTaken")
+ .desc("Number of Branches Predicted As Not Taken (False).");
+
+ Resource::regStats();
+}
+
+void
+BranchPredictor::execute(int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ ResourceRequest* bpred_req = reqMap[slot_num];
+
+ DynInstPtr inst = bpred_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ //int stage_num = bpred_req->getStageNum();
+
+ bpred_req->fault = NoFault;
+
+ switch (bpred_req->cmd)
+ {
+ case PredictBranch:
+ {
+ Addr pred_PC = inst->readNextPC();
+
+ if (inst->isControl()) {
+ // If predicted, the pred_PC will be updated to new target value
+ // If not, the pred_PC be updated to pc+8
+ bool predict_taken = branchPred.predict(inst, pred_PC, tid);
+
+ if (predict_taken) {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n",
+ tid, seq_num);
+
+ inst->setPredTarg(pred_PC);
+
+ predictedTaken++;
+ } else {
+ DPRINTF(InOrderBPred, "[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(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n",
+ tid, seq_num, pred_PC);
+
+ } else {
+ DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't "
+ "a control instruction.\n", tid, seq_num);
+ }
+
+ bpred_req->done();
+ }
+ break;
+
+ case UpdatePredictor:
+ {
+ DPRINTF(InOrderBPred, "[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(InOrderBPred, "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/o3/sparc/thread_context.hh b/src/cpu/inorder/resources/branch_predictor.hh
index 7497959e4..47053910d 100644
--- a/src/cpu/o3/sparc/thread_context.hh
+++ b/src/cpu/inorder/resources/branch_predictor.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,54 +25,62 @@
* (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: Gabe Black
+ * Authors: Korey Sewell
+ *
*/
-#include "arch/sparc/types.hh"
-#include "cpu/o3/thread_context.hh"
+#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"
+
+class BranchPredictor : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ PredictBranch,
+ UpdatePredictor
+ };
-template <class Impl>
-class SparcTC : public O3ThreadContext<Impl>
-{
public:
-#if FULL_SYSTEM
- /** Returns pointer to the quiesce event. */
- virtual EndQuiesceEvent *getQuiesceEvent()
- {
- return this->thread->quiesceEvent;
- }
-#endif
+ BranchPredictor(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
- virtual uint64_t readNextNPC()
- {
- return this->cpu->readNextNPC(this->thread->readTid());
- }
+ virtual void regStats();
- virtual void setNextNPC(uint64_t val)
- {
- this->cpu->setNextNPC(val, this->thread->readTid());
- }
+ virtual void execute(int slot_num);
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- //XXX Ignore this for now. This -really- needs to get fixed.
- }
+ virtual void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+ virtual void instGraduated(InstSeqNum seq_num,unsigned tid);
- /** 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.
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
*/
- virtual int exit()
- {
- this->deallocate();
+ BPredUnit branchPred;
+
+ int instSize;
+
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ Stats::Scalar predictedTaken;
+ Stats::Scalar predictedNotTaken;
- // If there are still threads executing in the system
- if (this->cpu->numActiveThreads())
- return 0; // don't exit simulation
- else
- return 1; // exit simulation
- }
};
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc
new file mode 100644
index 000000000..57bcb10ef
--- /dev/null
+++ b/src/cpu/inorder/resources/cache_unit.cc
@@ -0,0 +1,604 @@
+/*
+ * 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), cacheBlocked(false)
+{
+ cachePort = new CachePort(this);
+}
+
+Port *
+CacheUnit::getPort(const 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)
+ return -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 {
+ 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)
+{
+ 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]: 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 = 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;
+ }
+
+ 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);
+
+
+ // Get resource request info
+ // @todo: SMT needs to figure out where to get thread # from.
+ unsigned tid = 0;
+ 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 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] Miss on 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)
+{
+ 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(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:
+ panic("bad store data size = %d\n", packet->getSize());
+ }
+}
+
diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh
new file mode 100644
index 000000000..8cd2b89cb
--- /dev/null
+++ b/src/cpu/inorder/resources/cache_unit.hh
@@ -0,0 +1,315 @@
+/*
+ * 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()
+ {
+#if 0
+ 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;
+ }
+#endif
+
+ if (memReq)
+ delete memReq;
+ }
+
+ virtual PacketDataPtr getData()
+ { return reqData; }
+
+ void
+ setMemAccCompleted(bool completed = true)
+ {
+ memAccComplete = completed;
+ }
+
+ bool isMemAccComplete() { return memAccComplete; }
+
+ void setMemAccPending(bool pending = true) { memAccPending = pending; }
+ bool isMemAccPending() { return memAccPending; }
+
+ //Make this data private/protected!
+ MemCmd::Command pktCmd;
+ RequestPtr memReq;
+ PacketDataPtr reqData;
+ PacketPtr dataPkt;
+ PacketPtr retryPkt;
+
+ bool memAccComplete;
+ bool memAccPending;
+};
+
+class CacheReqPacket : public Packet
+{
+ public:
+ CacheReqPacket(CacheRequest *_req,
+ Command _cmd, short _dest)
+ : Packet(_req->memReq, _cmd, _dest), cacheReq(_req)
+ {
+
+ }
+
+ CacheRequest *cacheReq;
+};
+
+#endif //__CPU_CACHE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc
new file mode 100644
index 000000000..d95b1d4bb
--- /dev/null
+++ b/src/cpu/inorder/resources/decode_unit.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include "cpu/inorder/resources/decode_unit.hh"
+
+using namespace TheISA;
+using namespace ThePipeline;
+using namespace std;
+
+DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{
+ for (int tid = 0; tid < MaxThreads; tid++) {
+ regDepMap[tid] = &cpu->archRegDepMap[tid];
+ }
+}
+
+void
+DecodeUnit::execute(int slot_num)
+{
+ ResourceRequest* decode_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid, seq_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ decode_req->fault = NoFault;
+
+ switch (decode_req->cmd)
+ {
+ case DecodeInst:
+ {
+ bool done_sked = ThePipeline::createBackEndSchedule(inst);
+
+ if (done_sked) {
+ DPRINTF(InOrderDecode, "[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(InOrderDecode, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n",
+ tid, stage_num, squash_seq_num);
+
+ //cpu->removeInstsUntil(squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/decode_unit.hh b/src/cpu/inorder/resources/decode_unit.hh
new file mode 100644
index 000000000..3813de6c4
--- /dev/null
+++ b/src/cpu/inorder/resources/decode_unit.hh
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#ifndef __CPU_INORDER_DECODE_UNIT_HH__
+#define __CPU_INORDER_DECODE_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+
+class DecodeUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ DecodeUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~DecodeUnit() {}
+
+ enum Command {
+ DecodeInst
+ };
+
+ virtual void execute(int slot_num);
+
+ void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ RegDepMap *regDepMap[ThePipeline::MaxThreads];
+
+ protected:
+ /** @todo: Add Resource Stats Here */
+};
+
+#endif //__CPU_INORDER_DECODE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc
new file mode 100644
index 000000000..843adb5b0
--- /dev/null
+++ b/src/cpu/inorder/resources/execution_unit.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include <vector>
+#include <list>
+#include "cpu/inorder/resources/execution_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+ExecutionUnit::regStats()
+{
+ predictedTakenIncorrect
+ .name(name() + ".predictedTakenIncorrect")
+ .desc("Number of Branches Incorrectly Predicted As Taken.");
+
+ predictedNotTakenIncorrect
+ .name(name() + ".predictedNotTakenIncorrect")
+ .desc("Number of Branches Incorrectly Predicted As Not Taken).");
+
+ Resource::regStats();
+}
+
+void
+ExecutionUnit::execute(int slot_num)
+{
+ ResourceRequest* exec_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+
+ exec_req->fault = NoFault;
+
+ DPRINTF(InOrderExecute, "[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(InOrderExecute, "[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(InOrderExecute, "[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(InOrderExecute, "[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(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid,
+ inst->readPredTarg());
+
+ } else if(inst->isIndirectCtrl()){
+ inst->setPredTarg(inst->nextNPC);
+ inst->bdelaySeqNum = seq_num + 1;
+ DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid,
+ inst->readPredTarg());
+ } else {
+ panic("Non-control instruction (%s) mispredicting?!!",
+ inst->staticInst->getName());
+ }
+
+ DPRINTF(InOrderExecute, "[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(InOrderExecute, "[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/o3/mips/thread_context.hh b/src/cpu/inorder/resources/execution_unit.hh
index 26b1e2e7f..46691bbf2 100644
--- a/src/cpu/o3/mips/thread_context.hh
+++ b/src/cpu/inorder/resources/execution_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,44 +25,53 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-#include "arch/mips/types.hh"
-#include "cpu/o3/thread_context.hh"
+#ifndef __CPU_INORDER_EXECUTION_UNIT_HH__
+#define __CPU_INORDER_EXECUTION_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
-template <class Impl>
-class MipsTC : public O3ThreadContext<Impl>
-{
+#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:
- virtual uint64_t readNextNPC()
- {
- return this->cpu->readNextNPC(this->thread->readTid());
- }
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ ExecuteInst
+ };
- virtual void setNextNPC(uint64_t val)
- {
- this->cpu->setNextNPC(val, this->thread->readTid());
- }
+ public:
+ ExecutionUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~ExecutionUnit() {}
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- { panic("Not supported on Mips!"); }
+ public:
+ virtual void regStats();
- /** 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.
+ /** 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 int exit()
- {
- this->deallocate();
+ virtual void execute(int slot_num);
- // If there are still threads executing in the system
- if (this->cpu->numActiveThreads())
- return 0; // don't exit simulation
- else
- return 1; // exit simulation
- }
+ protected:
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ Stats::Scalar predictedTakenIncorrect;
+ Stats::Scalar predictedNotTakenIncorrect;
};
+
+
+#endif //__CPU_INORDER_EXCUTION_UNIT_HH__
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc
new file mode 100644
index 000000000..444252e1b
--- /dev/null
+++ b/src/cpu/inorder/resources/fetch_seq_unit.cc
@@ -0,0 +1,323 @@
+/*
+ * 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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[tid:%i]: [sn:%i] Updating delay slot target "
+ "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg());
+
+ // Set-Up Squash Through-Out Pipeline
+ DPRINTF(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[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(InOrderFetchSeq, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n",
+ tid, PC[tid], nextPC[tid], nextNPC[tid]);
+}
+
+void
+FetchSeqUnit::deactivateThread(unsigned tid)
+{
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ pcValid[tid] = false;
+ pcBlockStage[tid] = 0;
+
+ squashSeqNum[tid] = (InstSeqNum)-1;
+ lastSquashCycle[tid] = 0;
+
+ std::list<unsigned>::iterator thread_it = find(cpu->fetchPriorityList.begin(),
+ cpu->fetchPriorityList.end(),
+ tid);
+
+ if (thread_it != cpu->fetchPriorityList.end())
+ cpu->fetchPriorityList.erase(thread_it);
+}
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh
new file mode 100644
index 000000000..1885d1f11
--- /dev/null
+++ b/src/cpu/inorder/resources/fetch_seq_unit.hh
@@ -0,0 +1,117 @@
+/*
+ * 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"
+
+class FetchSeqUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ AssignNextPC,
+ UpdateTargetPC
+ };
+
+ public:
+ FetchSeqUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~FetchSeqUnit() {}
+
+ virtual void init();
+ virtual void activateThread(unsigned tid);
+ virtual void deactivateThread(unsigned tid);
+ virtual void execute(int slot_num);
+
+ /** Override default Resource squash sequence. This actually,
+ * looks in the global communication buffer to get squash
+ * info
+ */
+ virtual void squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid);
+
+
+ inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid);
+
+ protected:
+ unsigned instSize;
+
+ bool pcValid[ThePipeline::MaxThreads];
+ int pcBlockStage[ThePipeline::MaxThreads];
+
+ TheISA::IntReg PC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextPC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
+
+ /** Tracks delay slot information for threads in ISAs which use
+ * delay slots;
+ */
+ struct DelaySlotInfo {
+ InstSeqNum delaySlotSeqNum;
+ InstSeqNum branchSeqNum;
+ int numInsts;
+ Addr targetAddr;
+ bool targetReady;
+ };
+
+ DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads];
+
+ /** Squash Seq. Nums*/
+ InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
+
+ /** Squash Seq. Nums*/
+ Tick lastSquashCycle[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+
+ public:
+ class FetchSeqEvent : public ResourceEvent {
+ public:
+ /** Constructs a resource event. */
+ FetchSeqEvent();
+ virtual ~FetchSeqEvent() {}
+
+ /** Processes a resource event. */
+ virtual void process();
+ };
+
+};
+
+#endif
diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc
new file mode 100644
index 000000000..569401e4f
--- /dev/null
+++ b/src/cpu/inorder/resources/graduation_unit.cc
@@ -0,0 +1,112 @@
+/*
+ * 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(InOrderGraduation, "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(InOrderGraduation, "[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(InOrderGraduation, "[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/o3/alpha/params.hh b/src/cpu/inorder/resources/graduation_unit.hh
index 164c25312..ad222b119 100644
--- a/src/cpu/o3/alpha/params.hh
+++ b/src/cpu/inorder/resources/graduation_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,37 +25,46 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __CPU_O3_ALPHA_PARAMS_HH__
-#define __CPU_O3_ALPHA_PARAMS_HH__
-
-#include "cpu/o3/cpu.hh"
-#include "cpu/o3/params.hh"
-
-//Forward declarations
-namespace AlphaISA
-{
- class DTB;
- class ITB;
-}
-class MemObject;
-class Process;
-class System;
-
-/**
- * This file defines the parameters that will be used for the AlphaO3CPU.
- * 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.
- */
+#ifndef __CPU_INORDER_GRAD_UNIT_HH__
+#define __CPU_INORDER_GRAD_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
-class AlphaSimpleParams : public O3Params
-{
+#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];
- AlphaISA::ITB *itb;
- AlphaISA::DTB *dtb;
+ /** @todo: Add Resource Stats Here */
};
-#endif // __CPU_O3_ALPHA_PARAMS_HH__
+#endif //__CPU_INORDER_GRAD_UNIT_HH__
diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc
new file mode 100644
index 000000000..fafff1fa7
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer.cc
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+InstBuffer::regStats()
+{
+ instsBypassed
+ .name(name() + ".instsBypassed")
+ .desc("Number of Instructions Bypassed.");
+
+ Resource::regStats();
+}
+
+void
+InstBuffer::execute(int slot_idx)
+{
+ ResReqPtr ib_req = reqMap[slot_idx];
+ DynInstPtr inst = ib_req->inst;
+ int tid, seq_num, stage_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ stage_num = ib_req->getStageNum();
+ ib_req->fault = NoFault;
+
+ switch (ib_req->cmd)
+ {
+ case ScheduleOrBypass:
+ {
+ int next_stage = stage_num + 1;
+ int bypass_stage = stage_num + 2;
+ bool do_bypass = true;
+
+ if (!instList.empty()) {
+ DPRINTF(InOrderInstBuffer, "[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(InOrderInstBuffer, "[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(InOrderInstBuffer, "[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(InOrderInstBuffer, "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(InOrderInstBuffer, "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(InOrderInstBuffer, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
+ tid, seq_num);
+ insert(inst);
+ inserted = true;
+ } else {
+ DPRINTF(InOrderInstBuffer, "[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(InOrderInstBuffer, "[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(InOrderInstBuffer, "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(InOrderInstBuffer, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n",
+ tid, (*remove_list.front())->seqNum);
+ instList.erase(remove_list.front());
+ remove_list.pop();
+ }
+
+ Resource::squash(inst, stage_num, squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh
new file mode 100644
index 000000000..baadd42ff
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer.hh
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
+#define __CPU_INORDER_INST_BUFF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class InstBuffer : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ InsertInst,
+ InsertAddr,
+ RemoveInst,
+ RemoveAddr,
+ ScheduleOrBypass
+ };
+
+ public:
+ InstBuffer(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~InstBuffer() {}
+
+ virtual void regStats();
+
+ virtual void execute(int slot_num);
+
+ virtual void insert(DynInstPtr inst);
+
+ virtual void remove(DynInstPtr inst);
+
+ virtual void pop(unsigned tid);
+
+ virtual DynInstPtr top(unsigned tid);
+
+ virtual void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ public:
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar instsBypassed;
+
+};
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc
new file mode 100644
index 000000000..7e2c98837
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer_new.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+ResReqPtr
+InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top());
+ assert(ib_entry);
+
+ return new InstBufferRequest(this, inst, stage_num, id, slot_num,
+ ib_entry->cmd);
+}
+
+void
+InstBuffer::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]);
+ assert(ib_req);
+
+ DynInstPtr inst = ib_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ ib_req->fault = NoFault;
+
+ switch (ib_req->cmd)
+ {
+ case InsertInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
+ tid, seq_num);
+ insert(inst);
+ ib_req->done();
+ }
+ break;
+
+ case RemoveInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n",
+ tid, seq_num);
+ remove(inst);
+ ib_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+ DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size());
+}
+
+void
+InstBuffer::insert(DynInstPtr inst)
+{
+ instList.push_back(inst);
+}
+
+void
+InstBuffer::remove(DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ if((*list_it) == inst) {
+ instList.erase(list_it);
+ break;
+ }
+ list_it++;
+ }
+}
+
+void
+InstBuffer::pop()
+{ instList.pop_front(); }
+
+ThePipeline::DynInstPtr
+InstBuffer::top()
+{ return instList.front(); }
+
+void
+InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+ list<DynInstPtr>::iterator list_it = instList.begin();
+ list<DynInstPtr>::iterator list_end = instList.end();
+ queue<list<DynInstPtr>::iterator> remove_list;
+
+ // Collect All Instructions to be Removed in Remove List
+ while (list_it != list_end) {
+ if((*list_it)->seqNum > squash_seq_num) {
+ DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n",
+ tid, (*list_it)->seqNum);
+ (*list_it)->setSquashed();
+ remove_list.push(list_it);
+ }
+
+ list_it++;
+ }
+
+ // Removed Instructions from InstList & Clear Remove List
+ while (!remove_list.empty()) {
+ instList.erase(remove_list.front());
+ remove_list.pop();
+ }
+
+ Resource::squash(squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh
new file mode 100644
index 000000000..e374fa109
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer_new.hh
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
+#define __CPU_INORDER_INST_BUFF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class InstBuffer : public Resource {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ InsertInst,
+ InsertAddr,
+ RemoveInst,
+ RemoveAddr
+ };
+
+ public:
+ InstBuffer(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu);
+ virtual ~InstBuffer() {}
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num);
+
+ virtual void execute(int slot_num);
+
+ virtual void insert(DynInstPtr inst);
+
+ virtual void remove(DynInstPtr inst);
+
+ virtual void pop();
+
+ virtual DynInstPtr top();
+
+ virtual void squash(InstSeqNum squash_seq_num, unsigned tid);
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ /** @todo: Add Resource Stats Here */
+
+};
+
+struct InstBufferEntry : public ThePipeline::ScheduleEntry {
+ InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) :
+ ScheduleEntry(stage_num, res_num), cmd(_cmd)
+ { }
+
+ InstBuffer::Command cmd;
+};
+
+class InstBufferRequest : public ResourceRequest {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
+ InstBuffer::Command _cmd)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num),
+ cmd(_cmd)
+ { }
+
+ InstBuffer::Command cmd;
+};
+
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/o3/sparc/params.hh b/src/cpu/inorder/resources/mem_dep_unit.hh
index 09f523818..0bd850c5c 100644
--- a/src/cpu/o3/sparc/params.hh
+++ b/src/cpu/inorder/resources/mem_dep_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,37 +25,42 @@
* (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: Gabe Black
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __CPU_O3_SPARC_PARAMS_HH__
-#define __CPU_O3_SPARC_PARAMS_HH__
-
-#include "cpu/o3/cpu.hh"
-#include "cpu/o3/params.hh"
-
-//Forward declarations
-namespace SparcISA
-{
- class DTB;
- class ITB;
-}
-class MemObject;
-class Process;
-class System;
-
-/**
- * This file defines the parameters that will be used for the AlphaO3CPU.
- * 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.
- */
+#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;
-class SparcSimpleParams : public O3Params
-{
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];
- SparcISA::ITB *itb;
- SparcISA::DTB *dtb;
+ /** @todo: Add Resource Stats Here */
};
-#endif // __CPU_O3_SPARC_PARAMS_HH__
+#endif //__CPU_INORDER_GRAD_UNIT_HH__
diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc
new file mode 100644
index 000000000..b31d60ad5
--- /dev/null
+++ b/src/cpu/inorder/resources/mult_div_unit.cc
@@ -0,0 +1,285 @@
+/*
+ * 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),
+ lastMDUCycle(0)
+{ }
+
+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) {
+ lastMDUCycle = curTick;
+ lastOpType = inst->opClass();
+ lastInstName = inst->staticInst->getName();
+ }
+
+ return rval;
+ }
+}
+
+int
+MultDivUnit::getDivOpSize(DynInstPtr inst)
+{
+ // Get RT Register from instruction (index #1)
+ uint32_t div_op = inst->readIntSrc(1);
+
+ if (div_op <= 0xFF) {
+ return 8;
+ } else if (div_op <= 0xFFFF) {
+ return 16;
+ } else if (div_op <= 0xFFFFFF) {
+ return 24;
+ } else {
+ return 32;
+ }
+}
+
+void
+MultDivUnit::execute(int slot_num)
+{
+ ResourceRequest* mult_div_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+
+ //int tid = inst->readTid();
+ //int seq_num = inst->seqNum;
+
+ switch (mult_div_req->cmd)
+ {
+ case StartMultDiv:
+ DPRINTF(InOrderMDU, "Start MDU called ...\n");
+
+ if (inst->opClass() == IntMultOp) {
+ scheduleEvent(slot_num, multLatency);
+ multInstReqsProcessed++;
+ } else if (inst->opClass() == IntDivOp) {
+ int op_size = getDivOpSize(inst);
+
+ switch (op_size)
+ {
+ case 8:
+ scheduleEvent(slot_num, div8Latency);
+ break;
+
+ case 16:
+ scheduleEvent(slot_num, div16Latency);
+ break;
+
+ case 24:
+ scheduleEvent(slot_num, div24Latency);
+ break;
+
+ case 32:
+ scheduleEvent(slot_num, div32Latency);
+ break;
+ }
+
+ lastDivSize = op_size;
+
+ divInstReqsProcessed++;
+ }
+
+ // Allow to pass through to next stage while
+ // event processes
+ mult_div_req->setCompleted();
+ break;
+
+ case MultDiv:
+ DPRINTF(InOrderMDU, "Execute MDU called ...\n");
+ exeMulDiv(slot_num);
+ mult_div_req->done();
+ break;
+
+
+ case EndMultDiv:
+ //@TODO: Why not allow high-latency requests to sleep
+ // within stage until event wakes up????
+ // Seems wasteful to continually check to see if
+ // this is done when we have a event in parallel
+ // counting down the time
+ {
+ DPRINTF(InOrderMDU, "End MDU called ...\n");
+ if (mult_div_req->getInst()->isExecuted())
+ mult_div_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+void
+MultDivUnit::exeMulDiv(int slot_num)
+{
+ ResourceRequest* mult_div_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+
+ fault = inst->execute();
+
+ if (fault == NoFault) {
+ inst->setExecuted();
+ mult_div_req->setCompleted();
+
+ DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
+ inst->readTid(), inst->readIntResult(0));
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ cpu->trap(fault, tid);
+ }
+}
+
+
+MDUEvent::MDUEvent()
+ : ResourceEvent()
+{ }
+
+void
+MDUEvent::process()
+{
+ MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
+
+ mdu_res->exeMulDiv(slotIdx);
+
+ ResourceRequest* mult_div_req = resource->reqMap[slotIdx];
+
+ mult_div_req->done();
+}
+
+
diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh
new file mode 100644
index 000000000..76180714c
--- /dev/null
+++ b/src/cpu/inorder/resources/mult_div_unit.hh
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#ifndef __CPU_INORDER_MULT_DIV_UNIT_HH__
+#define __CPU_INORDER_MULT_DIV_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/op_class.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+
+class MDUEvent;
+
+class MultDivUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ StartMultDiv,
+ EndMultDiv,
+ MultDiv
+ };
+
+ public:
+ MultDivUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~MultDivUnit() {}
+
+ public:
+ /** Override default Resource getSlot(). Will only getSlot if
+ * valid mult/div sequence is being maintained
+ */
+ virtual int getSlot(DynInstPtr inst);
+
+ virtual int findSlot(DynInstPtr inst);
+
+ virtual void freeSlot(int slot_idx);
+
+ virtual void init();
+
+ /** Get Operand Size For A Division Operation */
+ int getDivOpSize(DynInstPtr inst);
+
+ /** Override default Resource execute */
+ virtual void execute(int slot_num);
+
+ void exeMulDiv(int slot_num);
+
+ /** Register extra resource stats */
+ virtual void regStats();
+
+ protected:
+ /** Latency & Repeat Rate for Multiply Insts */
+ unsigned multRepeatRate;
+ unsigned multLatency;
+
+ /** Latency & Repeat Rate for 8-bit Divide Insts */
+ unsigned div8RepeatRate;
+ unsigned div8Latency;
+
+ /** Latency & Repeat Rate for 16-bit Divide Insts */
+ unsigned div16RepeatRate;
+ unsigned div16Latency;
+
+ /** Latency & Repeat Rate for 24-bit Divide Insts */
+ unsigned div24RepeatRate;
+ unsigned div24Latency;
+
+ /** Latency & Repeat Rate for 32-bit Divide Insts */
+ unsigned div32RepeatRate;
+ unsigned div32Latency;
+
+ /** 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/o3/sparc/thread_context.cc b/src/cpu/inorder/resources/resource_list.hh
index d85aff502..cbe2ad8c3 100755..100644
--- a/src/cpu/o3/sparc/thread_context.cc
+++ b/src/cpu/inorder/resources/resource_list.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,11 +25,23 @@
* (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: Gabe Black
+ * Authors: Korey Sewell
+ *
*/
-#include "cpu/o3/thread_context.hh"
-#include "cpu/o3/thread_context_impl.hh"
+#ifndef CPU_INORDER_RESOURCE_LIST_HH
+#define CPU_INORDER_RESOURCE_LIST_HH
-template class O3ThreadContext<SparcSimpleImpl>;
+#include "cpu/inorder/resources/cache_unit.hh"
+#include "cpu/inorder/resources/execution_unit.hh"
+#include "cpu/inorder/resources/use_def.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/resources/decode_unit.hh"
+#include "cpu/inorder/resources/graduation_unit.hh"
+#include "cpu/inorder/resources/tlb_unit.hh"
+#include "cpu/inorder/resources/fetch_seq_unit.hh"
+#include "cpu/inorder/resources/branch_predictor.hh"
+#include "cpu/inorder/resources/agen_unit.hh"
+#include "cpu/inorder/resources/mult_div_unit.hh"
+#endif
diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc
new file mode 100644
index 000000000..8f8ba144e
--- /dev/null
+++ b/src/cpu/inorder/resources/tlb_unit.cc
@@ -0,0 +1,188 @@
+/*
+ * 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->itb->translateAtomic(tlb_req->memReq,
+ cpu->thread[tid]->getTC());
+
+ if (tlb_req->fault != NoFault) {
+ DPRINTF(InOrderTLB, "[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(InOrderTLB, "[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(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
+ tid, seq_num, tlb_req->memReq->getVaddr());
+
+ tlb_req->fault =
+ this->cpu->itb->translateAtomic(tlb_req->memReq,
+ cpu->thread[tid]->getTC());
+
+ if (tlb_req->fault != NoFault) {
+ DPRINTF(InOrderTLB, "[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(InOrderTLB, "[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(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n",
+ inst->seqNum);
+
+ TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource);
+ assert(tlb_res);
+
+ tlb_res->tlbBlocked[tid] = false;
+
+ tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid);
+
+ // Effectively NOP the instruction but still allow it
+ // to commit
+ //while (!inst->resSched.empty() &&
+ // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) {
+ //inst->resSched.pop();
+ //}
+}
diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh
new file mode 100644
index 000000000..c7fee6030
--- /dev/null
+++ b/src/cpu/inorder/resources/tlb_unit.hh
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#ifndef __CPU_INORDER_TLB_UNIT_HH__
+#define __CPU_INORDER_TLB_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class TLBUnit : public InstBuffer {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum TLBCommand {
+ FetchLookup,
+ DataLookup
+ };
+
+ public:
+ TLBUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~TLBUnit() {}
+
+ void init();
+
+ int getSlot(DynInstPtr inst);
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ virtual void execute(int slot_num);
+
+ bool tlbBlocked[ThePipeline::MaxThreads];
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ /** @todo: Add Resource Stats Here */
+
+};
+
+class TLBUnitEvent : public ResourceEvent {
+ public:
+ /** Constructs a resource event. */
+ TLBUnitEvent();
+ virtual ~TLBUnitEvent() {}
+
+ /** Processes a resource event. */
+ virtual void process();
+};
+
+class TLBUnitRequest : public ResourceRequest {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
+ unsigned _cmd)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd)
+ {
+ Addr aligned_addr;
+ int req_size;
+ unsigned flags;
+
+ if (_cmd == TLBUnit::FetchLookup) {
+ aligned_addr = inst->getMemAddr();
+ req_size = sizeof(MachInst);
+ flags = 0;
+ } else {
+ aligned_addr = inst->getMemAddr();;
+ req_size = inst->getMemAccSize();
+ flags = inst->getMemFlags();
+ }
+
+ // @TODO: Add Vaddr & Paddr functions
+ inst->memReq = new Request(inst->readTid(), aligned_addr, req_size,
+ flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid());
+
+ memReq = inst->memReq;
+ }
+
+ RequestPtr memReq;
+};
+
+
+#endif //__CPU_INORDER_TLB_UNIT_HH__
diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc
new file mode 100644
index 000000000..a9281a18c
--- /dev/null
+++ b/src/cpu/inorder/resources/use_def.cc
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#include <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/use_def.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ maxSeqNum((InstSeqNum)-1)
+{
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
+ nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
+
+ outReadSeqNum[tid] = maxSeqNum;
+ outWriteSeqNum[tid] = maxSeqNum;
+
+ regDepMap[tid] = &cpu->archRegDepMap[tid];
+ }
+}
+
+ResReqPtr
+UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd)
+{
+ return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd,
+ inst->resSched.top()->idx);
+}
+
+
+ResReqPtr
+UseDefUnit::findRequest(DynInstPtr inst)
+{
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>((*map_it).second);
+ assert(ud_req);
+
+ if (ud_req &&
+ ud_req->getInst() == inst &&
+ ud_req->cmd == inst->resSched.top()->cmd &&
+ ud_req->useDefIdx == inst->resSched.top()->idx) {
+ return ud_req;
+ }
+ map_it++;
+ }
+
+ return NULL;
+}
+
+void
+UseDefUnit::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqMap[slot_idx]);
+ assert(ud_req);
+
+ DynInstPtr inst = ud_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ int ud_idx = ud_req->useDefIdx;
+
+ // If there is a non-speculative instruction
+ // in the pipeline then stall instructions here
+ if (*nonSpecInstActive[tid] == true &&
+ seq_num > *nonSpecSeqNum[tid]) {
+ DPRINTF(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[tid:%i]: Attempting to write to Register File.\n",
+ tid);
+
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[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(InOrderUseDef, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid);
+ outReadSeqNum[tid] = maxSeqNum;
+ } else if (outReadSeqNum[tid] != maxSeqNum) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n",
+ tid, outReadSeqNum[tid]);
+ }
+
+ if (outWriteSeqNum[tid] >= squash_seq_num) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid);
+ outWriteSeqNum[tid] = maxSeqNum;
+ } else if (outWriteSeqNum[tid] != maxSeqNum) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n",
+ tid, outWriteSeqNum[tid]);
+ }
+}
diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh
new file mode 100644
index 000000000..238591117
--- /dev/null
+++ b/src/cpu/inorder/resources/use_def.hh
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ *
+ */
+
+#ifndef __CPU_INORDER_USE_DEF_UNIT_HH__
+#define __CPU_INORDER_USE_DEF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+
+class UseDefUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ ReadSrcReg,
+ WriteDestReg
+ };
+
+ public:
+ UseDefUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~UseDefUnit() {}
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ virtual ResReqPtr findRequest(DynInstPtr inst);
+
+ virtual void execute(int slot_num);
+
+ virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ const InstSeqNum maxSeqNum;
+
+ protected:
+ RegDepMap *regDepMap[ThePipeline::MaxThreads];
+
+ /** Outstanding Seq. Num. Trying to Read from Register File */
+ InstSeqNum outReadSeqNum[ThePipeline::MaxThreads];
+
+ InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads];
+
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
+
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+
+ public:
+ class UseDefRequest : public ResourceRequest {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd, int use_def_idx)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd),
+ useDefIdx(use_def_idx)
+ { }
+
+ int useDefIdx;
+ };
+};
+
+#endif //__CPU_INORDER_USE_DEF_UNIT_HH__
diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc
new file mode 100644
index 000000000..13f8ecdad
--- /dev/null
+++ b/src/cpu/inorder/thread_context.cc
@@ -0,0 +1,264 @@
+/*
+ * 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);
+
+ 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;
+
+ thread->setStatus(ThreadContext::Active);
+
+ 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 *src_tc)
+{
+ TheISA::copyRegs(src_tc, this);
+}
+
+
+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());
+}
+
+void
+InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+ cpu->setFloatReg(reg_idx, val, thread->readTid(), width);
+}
+
+void
+InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val)
+{
+ cpu->setFloatReg(reg_idx, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val,
+ int width)
+{
+ cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width);
+}
+
+void
+InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+ cpu->setFloatRegBits(reg_idx, val, 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());
+}
+
+void
+InOrderThreadContext::setNextPC(uint64_t val)
+{
+ DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val);
+ cpu->setNextPC(val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setNextNPC(uint64_t val)
+{
+ DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val);
+ cpu->setNextNPC(val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+{
+ cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ cpu->setMiscReg(misc_reg, val, thread->readTid());
+}
diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh
new file mode 100644
index 000000000..2fb2ed85f
--- /dev/null
+++ b/src/cpu/inorder/thread_context.hh
@@ -0,0 +1,275 @@
+/*
+ * 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); }
+
+ /** 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 *src_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; }
+
+ /** 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
index 000000000..eb4fe40b2
--- /dev/null
+++ b/src/cpu/inorder/thread_state.hh
@@ -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__
diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh
index 5d5bcda8e..e34658b58 100644
--- a/src/cpu/inteltrace.hh
+++ b/src/cpu/inteltrace.hh
@@ -47,8 +47,10 @@ class IntelTraceRecord : public InstRecord
{
public:
IntelTraceRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc)
{
}
@@ -64,7 +66,8 @@ class IntelTrace : public InstTracer
IntelTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (!IsOn(ExecEnable))
return NULL;
@@ -76,7 +79,7 @@ class IntelTrace : public InstTracer
return NULL;
return new IntelTraceRecord(when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
};
diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc
index c3a11ad91..de7f9245e 100644
--- a/src/cpu/intr_control.cc
+++ b/src/cpu/intr_control.cc
@@ -50,7 +50,7 @@ IntrControl::post(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
- cpu->post_interrupt(int_num, index);
+ cpu->postInterrupt(int_num, index);
}
void
@@ -59,7 +59,7 @@ IntrControl::clear(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
- cpu->clear_interrupt(int_num, index);
+ cpu->clearInterrupt(int_num, index);
}
IntrControl *
diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh
index 97193ff1a..9962063e4 100644
--- a/src/cpu/legiontrace.hh
+++ b/src/cpu/legiontrace.hh
@@ -46,8 +46,10 @@ class LegionTraceRecord : public InstRecord
{
public:
LegionTraceRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc)
{
}
@@ -63,13 +65,14 @@ class LegionTrace : public InstTracer
LegionTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (tc->misspeculating())
return NULL;
return new LegionTraceRecord(when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
};
diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc
index 42889163a..3c57f85b7 100644
--- a/src/cpu/memtest/memtest.cc
+++ b/src/cpu/memtest/memtest.cc
@@ -152,7 +152,7 @@ MemTest::MemTest(const Params *p)
// set up counters
noResponseCycles = 0;
numReads = 0;
- tickEvent.schedule(0);
+ schedule(tickEvent, 0);
id = TESTER_ALLOCATOR++;
@@ -262,7 +262,7 @@ void
MemTest::tick()
{
if (!tickEvent.scheduled())
- tickEvent.schedule(curTick + ticks(1));
+ schedule(tickEvent, curTick + ticks(1));
if (++noResponseCycles >= 500000) {
cerr << name() << ": deadlocked at cycle " << curTick << endl;
@@ -279,7 +279,7 @@ MemTest::tick()
unsigned base = random() % 2;
uint64_t data = random();
unsigned access_size = random() % 4;
- unsigned cacheable = random() % 100;
+ bool uncacheable = (random() % 100) < percentUncacheable;
//If we aren't doing copies, use id as offset, and do a false sharing
//mem tester
@@ -290,17 +290,16 @@ MemTest::tick()
access_size = 0;
Request *req = new Request();
- uint32_t flags = 0;
+ Request::Flags flags;
Addr paddr;
- if (cacheable < percentUncacheable) {
- flags |= UNCACHEABLE;
+ if (uncacheable) {
+ flags.set(Request::UNCACHEABLE);
paddr = uncacheAddr + offset;
} else {
paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
}
- bool probe = (random() % 100 < percentFunctional) && !(flags & UNCACHEABLE);
- //bool probe = false;
+ bool probe = (random() % 100 < percentFunctional) && !uncacheable;
paddr &= ~((1 << access_size) - 1);
req->setPhys(paddr, 1 << access_size, flags);
diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh
index ac2d0a058..907659f69 100644
--- a/src/cpu/memtest/memtest.hh
+++ b/src/cpu/memtest/memtest.hh
@@ -35,6 +35,7 @@
#include <set>
#include "base/statistics.hh"
+#include "base/fast_alloc.hh"
#include "params/MemTest.hh"
#include "sim/eventq.hh"
#include "sim/sim_exit.hh"
@@ -73,10 +74,10 @@ class MemTest : public MemObject
{
private:
MemTest *cpu;
+
public:
- TickEvent(MemTest *c)
- : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {}
- void process() {cpu->tick();}
+ TickEvent(MemTest *c) : Event(CPU_Tick_Pri), cpu(c) {}
+ void process() { cpu->tick(); }
virtual const char *description() const { return "MemTest tick"; }
};
@@ -116,7 +117,7 @@ class MemTest : public MemObject
bool snoopRangeSent;
- class MemTestSenderState : public Packet::SenderState
+ class MemTestSenderState : public Packet::SenderState, public FastAlloc
{
public:
/** Constructor. */
@@ -132,10 +133,10 @@ class MemTest : public MemObject
bool accessRetry;
- unsigned size; // size of testing memory region
+ unsigned size; // size of testing memory region
- unsigned percentReads; // target percentage of read accesses
- unsigned percentFunctional; // target percentage of functional accesses
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentFunctional; // target percentage of functional accesses
unsigned percentUncacheable;
int id;
@@ -153,12 +154,12 @@ class MemTest : public MemObject
Addr traceBlockAddr;
- Addr baseAddr1; // fix this to option
- Addr baseAddr2; // fix this to option
+ Addr baseAddr1; // fix this to option
+ Addr baseAddr2; // fix this to option
Addr uncacheAddr;
- unsigned progressInterval; // frequency of progress reports
- Tick nextProgressMessage; // access # for next progress report
+ unsigned progressInterval; // frequency of progress reports
+ Tick nextProgressMessage; // access # for next progress report
unsigned percentSourceUnaligned;
unsigned percentDestUnaligned;
@@ -170,9 +171,9 @@ class MemTest : public MemObject
bool atomic;
- Stats::Scalar<> numReadsStat;
- Stats::Scalar<> numWritesStat;
- Stats::Scalar<> numCopiesStat;
+ Stats::Scalar numReadsStat;
+ Stats::Scalar numWritesStat;
+ Stats::Scalar numCopiesStat;
// called by MemCompleteEvent::process()
void completeRequest(PacketPtr pkt);
diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc
index 7152602fe..c23a9e4ad 100644
--- a/src/cpu/nativetrace.cc
+++ b/src/cpu/nativetrace.cc
@@ -50,8 +50,12 @@ using namespace TheISA;
namespace Trace {
-NativeTrace::NativeTrace(const Params *p) : InstTracer(p)
+NativeTrace::NativeTrace(const Params *p)
+ : InstTracer(p)
{
+ if (ListenSocket::allDisabled())
+ fatal("All listeners are disabled!");
+
int port = 8000;
while(!native_listener.listen(port, true))
{
diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh
index ab038c4c3..9e912d92f 100644
--- a/src/cpu/nativetrace.hh
+++ b/src/cpu/nativetrace.hh
@@ -54,8 +54,11 @@ class NativeTraceRecord : public InstRecord
public:
NativeTraceRecord(NativeTrace * _parent,
Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc),
+ parent(_parent)
{
}
@@ -192,13 +195,14 @@ class NativeTrace : public InstTracer
NativeTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (tc->misspeculating())
return NULL;
return new NativeTraceRecord(this, when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
void
diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py
index f0284b2cf..56e537ad2 100644
--- a/src/cpu/o3/O3CPU.py
+++ b/src/cpu/o3/O3CPU.py
@@ -38,10 +38,7 @@ if build_env['USE_CHECKER']:
class DerivO3CPU(BaseCPU):
type = 'DerivO3CPU'
activity = Param.Unsigned(0, "Initial count")
- numThreads = Param.Unsigned(1, "number of HW thread contexts")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
if build_env['USE_CHECKER']:
if not build_env['FULL_SYSTEM']:
checker = Param.BaseCPU(O3Checker(workload=Parent.workload,
@@ -134,9 +131,6 @@ class DerivO3CPU(BaseCPU):
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
- function_trace = Param.Bool(False, "Enable function trace")
- function_trace_start = Param.Tick(0, "Cycle to start function trace")
-
smtNumFetchingThreads = Param.Unsigned(1, "SMT Number of Fetching Threads")
smtFetchPolicy = Param.String('SingleThread', "SMT Fetch policy")
smtLSQPolicy = Param.String('Partitioned', "SMT LSQ Sharing Policy")
diff --git a/src/cpu/o3/O3Checker.py b/src/cpu/o3/O3Checker.py
index 43a71d67b..edc6dc9b6 100644
--- a/src/cpu/o3/O3Checker.py
+++ b/src/cpu/o3/O3Checker.py
@@ -39,5 +39,3 @@ class O3Checker(BaseCPU):
"If a load result is incorrect, only print a warning and do not exit")
function_trace = Param.Bool(False, "Enable function trace")
function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript
index 2de106d8b..f05986bf5 100755
--- a/src/cpu/o3/SConscript
+++ b/src/cpu/o3/SConscript
@@ -51,7 +51,9 @@ if 'O3CPU' in env['CPU_MODELS']:
Source('bpred_unit.cc')
Source('commit.cc')
Source('cpu.cc')
+ Source('cpu_builder.cc')
Source('decode.cc')
+ Source('dyn_inst.cc')
Source('fetch.cc')
Source('free_list.cc')
Source('fu_pool.cc')
@@ -65,6 +67,7 @@ if 'O3CPU' in env['CPU_MODELS']:
Source('rob.cc')
Source('scoreboard.cc')
Source('store_set.cc')
+ Source('thread_context.cc')
TraceFlag('FreeList')
TraceFlag('LSQ')
@@ -81,24 +84,6 @@ if 'O3CPU' in env['CPU_MODELS']:
'IQ', 'ROB', 'FreeList', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit',
'DynInst', 'O3CPU', 'Activity', 'Scoreboard', 'Writeback' ])
- if env['TARGET_ISA'] == 'alpha':
- Source('alpha/cpu.cc')
- Source('alpha/cpu_builder.cc')
- Source('alpha/dyn_inst.cc')
- Source('alpha/thread_context.cc')
- elif env['TARGET_ISA'] == 'mips':
- Source('mips/cpu.cc')
- Source('mips/cpu_builder.cc')
- Source('mips/dyn_inst.cc')
- Source('mips/thread_context.cc')
- elif env['TARGET_ISA'] == 'sparc':
- Source('sparc/cpu.cc')
- Source('sparc/cpu_builder.cc')
- Source('sparc/dyn_inst.cc')
- Source('sparc/thread_context.cc')
- else:
- sys.exit('O3 CPU does not support the \'%s\' ISA' % env['TARGET_ISA'])
-
if env['USE_CHECKER']:
SimObject('O3Checker.py')
Source('checker_builder.cc')
diff --git a/src/cpu/o3/alpha/cpu.cc b/src/cpu/o3/alpha/cpu.cc
deleted file mode 100644
index ed10b2fd1..000000000
--- a/src/cpu/o3/alpha/cpu.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 "cpu/o3/alpha/impl.hh"
-#include "cpu/o3/alpha/cpu_impl.hh"
-#include "cpu/o3/alpha/dyn_inst.hh"
-
-// Force instantiation of AlphaO3CPU for all the implemntations that are
-// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all
-// classes that depend on a certain impl, into one file (alpha_impl.cc?).
-template class AlphaO3CPU<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh
deleted file mode 100644
index ebc4e7b23..000000000
--- a/src/cpu/o3/alpha/cpu.hh
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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
- */
-
-#ifndef __CPU_O3_ALPHA_CPU_HH__
-#define __CPU_O3_ALPHA_CPU_HH__
-
-#include "arch/regfile.hh"
-#include "arch/types.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/o3/cpu.hh"
-#include "sim/byteswap.hh"
-
-class EndQuiesceEvent;
-namespace Kernel {
- class Statistics;
-};
-
-class TranslatingPort;
-
-/**
- * AlphaO3CPU class. Derives from the FullO3CPU class, and
- * implements all ISA and implementation specific functions of the
- * CPU. This is the CPU class that is used for the SimObjects, and is
- * what is given to the DynInsts. Most of its state exists in the
- * FullO3CPU; the state is has is mainly for ISA specific
- * functionality.
- */
-template <class Impl>
-class AlphaO3CPU : public FullO3CPU<Impl>
-{
- public:
- typedef O3ThreadState<Impl> ImplState;
- typedef O3ThreadState<Impl> Thread;
- typedef typename Impl::Params Params;
-
- /** Constructs an AlphaO3CPU with the given parameters. */
- AlphaO3CPU(Params *params);
-
- /** Registers statistics. */
- void regStats();
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
-
- /** Reads a misc. register, including any side effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::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 TheISA::MiscReg &val,
- unsigned tid);
-
- /** Initiates a squash of all in-flight instructions for a given
- * thread. The source of the squash is an external update of
- * state through the TC.
- */
- void squashFromTC(unsigned tid);
-
-#if FULL_SYSTEM
- /** Posts an interrupt. */
- void post_interrupt(int int_num, int index);
- /** HW return from error interrupt. */
- Fault hwrei(unsigned tid);
-
- bool simPalCheck(int palFunc, unsigned tid);
-
- /** Returns the Fault for any valid interrupt. */
- Fault getInterrupts();
-
- /** Processes any an interrupt fault. */
- void processInterrupts(Fault interrupt);
-
- /** Halts the CPU. */
- void halt() { panic("Halt not implemented!\n"); }
-#endif
-
- /** Traps to handle given fault. */
- void trap(Fault fault, unsigned tid);
-
-#if !FULL_SYSTEM
- /** Executes a syscall.
- * @todo: Determine if this needs to be virtual.
- */
- void syscall(int64_t callnum, int tid);
- /** Gets a syscall argument. */
- TheISA::IntReg getSyscallArg(int i, int tid);
-
- /** Used to shift args for indirect syscall. */
- void setSyscallArg(int i, TheISA::IntReg val, int tid);
-
- /** Sets the return value of a syscall. */
- void setSyscallReturn(SyscallReturn return_value, int tid);
-#endif
-
- /** CPU read function, forwards read to LSQ. */
- template <class T>
- Fault read(RequestPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- /** CPU write function, forwards write to LSQ. */
- template <class T>
- Fault write(RequestPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
- Addr lockAddr;
-
- /** Temporary fix for the lock flag, works in the UP case. */
- bool lockFlag;
-};
-
-#endif // __CPU_O3_ALPHA_CPU_HH__
diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc
deleted file mode 100644
index f569c048b..000000000
--- a/src/cpu/o3/alpha/cpu_builder.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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
- */
-
-#include <string>
-
-#include "config/use_checker.hh"
-#include "cpu/base.hh"
-#include "cpu/o3/alpha/cpu.hh"
-#include "cpu/o3/alpha/impl.hh"
-#include "cpu/o3/alpha/params.hh"
-#include "cpu/o3/fu_pool.hh"
-#include "params/DerivO3CPU.hh"
-
-class DerivO3CPU : public AlphaO3CPU<AlphaSimpleImpl>
-{
- public:
- DerivO3CPU(AlphaSimpleParams *p)
- : AlphaO3CPU<AlphaSimpleImpl>(p)
- { }
-};
-
-DerivO3CPU *
-DerivO3CPUParams::create()
-{
- DerivO3CPU *cpu;
-
-#if FULL_SYSTEM
- // Full-system only supports a single thread for the moment.
- int actual_num_threads = 1;
-#else
- // In non-full-system mode, we infer the number of threads from
- // the workload if it's not explicitly specified.
- int actual_num_threads =
- (numThreads >= workload.size()) ? numThreads : workload.size();
-
- if (workload.size() == 0) {
- fatal("Must specify at least one workload!");
- }
-#endif
-
- AlphaSimpleParams *params = new AlphaSimpleParams;
-
- params->clock = clock;
- params->phase = phase;
-
- params->tracer = tracer;
-
- params->name = name;
- params->numberOfThreads = actual_num_threads;
- params->cpu_id = cpu_id;
- params->activity = activity;
-
- params->itb = itb;
- params->dtb = dtb;
-
- params->system = system;
-#if FULL_SYSTEM
- params->profile = profile;
-
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
- params->workload = workload;
-#endif // FULL_SYSTEM
-
-#if USE_CHECKER
- params->checker = checker;
-#endif
-
- params->max_insts_any_thread = max_insts_any_thread;
- params->max_insts_all_threads = max_insts_all_threads;
- params->max_loads_any_thread = max_loads_any_thread;
- params->max_loads_all_threads = max_loads_all_threads;
- params->progress_interval = progress_interval;
-
- //
- // Caches
- //
- params->cachePorts = cachePorts;
-
- params->decodeToFetchDelay = decodeToFetchDelay;
- params->renameToFetchDelay = renameToFetchDelay;
- params->iewToFetchDelay = iewToFetchDelay;
- params->commitToFetchDelay = commitToFetchDelay;
- params->fetchWidth = fetchWidth;
-
- params->renameToDecodeDelay = renameToDecodeDelay;
- params->iewToDecodeDelay = iewToDecodeDelay;
- params->commitToDecodeDelay = commitToDecodeDelay;
- params->fetchToDecodeDelay = fetchToDecodeDelay;
- params->decodeWidth = decodeWidth;
-
- params->iewToRenameDelay = iewToRenameDelay;
- params->commitToRenameDelay = commitToRenameDelay;
- params->decodeToRenameDelay = decodeToRenameDelay;
- params->renameWidth = renameWidth;
-
- params->commitToIEWDelay = commitToIEWDelay;
- params->renameToIEWDelay = renameToIEWDelay;
- params->issueToExecuteDelay = issueToExecuteDelay;
- params->dispatchWidth = dispatchWidth;
- params->issueWidth = issueWidth;
- params->wbWidth = wbWidth;
- params->wbDepth = wbDepth;
- params->fuPool = fuPool;
-
- params->iewToCommitDelay = iewToCommitDelay;
- params->renameToROBDelay = renameToROBDelay;
- params->commitWidth = commitWidth;
- params->squashWidth = squashWidth;
- params->trapLatency = trapLatency;
-
- params->backComSize = backComSize;
- params->forwardComSize = forwardComSize;
-
- params->predType = predType;
- params->localPredictorSize = localPredictorSize;
- params->localCtrBits = localCtrBits;
- params->localHistoryTableSize = localHistoryTableSize;
- params->localHistoryBits = localHistoryBits;
- params->globalPredictorSize = globalPredictorSize;
- params->globalCtrBits = globalCtrBits;
- params->globalHistoryBits = globalHistoryBits;
- params->choicePredictorSize = choicePredictorSize;
- params->choiceCtrBits = choiceCtrBits;
-
- params->BTBEntries = BTBEntries;
- params->BTBTagSize = BTBTagSize;
-
- params->RASSize = RASSize;
-
- params->LQEntries = LQEntries;
- params->SQEntries = SQEntries;
-
- params->SSITSize = SSITSize;
- params->LFSTSize = LFSTSize;
-
- params->numPhysIntRegs = numPhysIntRegs;
- params->numPhysFloatRegs = numPhysFloatRegs;
- params->numIQEntries = numIQEntries;
- params->numROBEntries = numROBEntries;
-
- params->smtNumFetchingThreads = smtNumFetchingThreads;
-
- // Default smtFetchPolicy to "RoundRobin", if necessary.
- std::string round_robin_policy = "RoundRobin";
- std::string single_thread = "SingleThread";
-
- if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
- params->smtFetchPolicy = round_robin_policy;
- else
- params->smtFetchPolicy = smtFetchPolicy;
-
- params->smtIQPolicy = smtIQPolicy;
- params->smtLSQPolicy = smtLSQPolicy;
- params->smtLSQThreshold = smtLSQThreshold;
- params->smtROBPolicy = smtROBPolicy;
- params->smtROBThreshold = smtROBThreshold;
- params->smtCommitPolicy = smtCommitPolicy;
-
- params->instShiftAmt = 2;
-
- params->deferRegistration = defer_registration;
-
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
-
- cpu = new DerivO3CPU(params);
-
- return cpu;
-}
diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh
deleted file mode 100644
index 7f8f0547b..000000000
--- a/src/cpu/o3/alpha/cpu_impl.hh
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * 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
- */
-
-#include "config/use_checker.hh"
-
-#include "arch/alpha/faults.hh"
-#include "arch/alpha/isa_traits.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "cpu/checker/thread_context.hh"
-#include "sim/sim_events.hh"
-#include "sim/stats.hh"
-
-#include "cpu/o3/alpha/cpu.hh"
-#include "cpu/o3/alpha/params.hh"
-#include "cpu/o3/alpha/thread_context.hh"
-#include "cpu/o3/comm.hh"
-#include "cpu/o3/thread_state.hh"
-
-#if FULL_SYSTEM
-#include "arch/alpha/osfpal.hh"
-#include "arch/isa_traits.hh"
-#include "arch/kernel_stats.hh"
-#include "cpu/quiesce_event.hh"
-#include "sim/sim_exit.hh"
-#include "sim/system.hh"
-#endif
-
-template <class Impl>
-AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) : FullO3CPU<Impl>(this, params)
-{
- DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n");
-
- // Setup any thread state.
- this->thread.resize(this->numThreads);
-
- for (int i = 0; i < this->numThreads; ++i) {
-#if FULL_SYSTEM
- // SMT is not supported in FS mode yet.
- assert(this->numThreads == 1);
- this->thread[i] = new Thread(this, 0);
- this->thread[i]->setStatus(ThreadContext::Suspended);
-#else
- if (i < params->workload.size()) {
- DPRINTF(O3CPU, "Workload[%i] process is %#x",
- i, this->thread[i]);
- this->thread[i] = new Thread(this, i, params->workload[i], i);
-
- this->thread[i]->setStatus(ThreadContext::Suspended);
-
- //usedTids[i] = true;
- //threadMap[i] = i;
- } else {
- //Allocate Empty thread so M5 can use later
- //when scheduling threads to CPU
- Process* dummy_proc = NULL;
-
- this->thread[i] = new Thread(this, i, dummy_proc, i);
- //usedTids[i] = false;
- }
-#endif // !FULL_SYSTEM
-
- ThreadContext *tc;
-
- // Setup the TC that will serve as the interface to the threads/CPU.
- AlphaTC<Impl> *alpha_tc =
- new AlphaTC<Impl>;
-
- tc = alpha_tc;
-
- // If we're using a checker, then the TC should be the
- // CheckerThreadContext.
-#if USE_CHECKER
- if (params->checker) {
- tc = new CheckerThreadContext<AlphaTC<Impl> >(
- alpha_tc, this->checker);
- }
-#endif
-
- alpha_tc->cpu = this;
- alpha_tc->thread = this->thread[i];
-
-#if FULL_SYSTEM
- // Setup quiesce event.
- this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc);
-#endif
- // Give the thread the TC.
- this->thread[i]->tc = tc;
- this->thread[i]->setCpuId(params->cpu_id);
-
- // Add the TC to the CPU's list of TC's.
- this->threadContexts.push_back(tc);
- }
-
- for (int i=0; i < this->numThreads; i++) {
- this->thread[i]->setFuncExeInst(0);
- }
-
- lockAddr = 0;
- lockFlag = false;
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::regStats()
-{
- // Register stats for everything that has stats.
- this->fullCPURegStats();
- this->fetch.regStats();
- this->decode.regStats();
- this->rename.regStats();
- this->iew.regStats();
- this->commit.regStats();
-}
-
-
-template <class Impl>
-TheISA::MiscReg
-AlphaO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscRegNoEffect(misc_reg, tid);
-}
-
-template <class Impl>
-TheISA::MiscReg
-AlphaO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscReg(misc_reg, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val,
- unsigned tid)
-{
- this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setMiscReg(int misc_reg,
- const TheISA::MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscReg(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::squashFromTC(unsigned tid)
-{
- this->thread[tid]->inSyscall = true;
- this->commit.generateTCEvent(tid);
-}
-
-#if FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::post_interrupt(int int_num, int index)
-{
- BaseCPU::post_interrupt(int_num, index);
-
- if (this->thread[0]->status() == ThreadContext::Suspended) {
- DPRINTF(IPI,"Suspended Processor awoke\n");
- this->threadContexts[0]->activate();
- }
-}
-
-template <class Impl>
-Fault
-AlphaO3CPU<Impl>::hwrei(unsigned tid)
-{
- // Need to clear the lock flag upon returning from an interrupt.
- this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
-
- this->thread[tid]->kernelStats->hwrei();
-
- // FIXME: XXX check for interrupts? XXX
- return NoFault;
-}
-
-template <class Impl>
-bool
-AlphaO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid)
-{
- if (this->thread[tid]->kernelStats)
- this->thread[tid]->kernelStats->callpal(palFunc,
- this->threadContexts[tid]);
-
- switch (palFunc) {
- case PAL::halt:
- halt();
- if (--System::numSystemsRunning == 0)
- exitSimLoop("all cpus halted");
- break;
-
- case PAL::bpt:
- case PAL::bugchk:
- if (this->system->breakpoint())
- return false;
- break;
- }
-
- return true;
-}
-
-template <class Impl>
-Fault
-AlphaO3CPU<Impl>::getInterrupts()
-{
- // Check if there are any outstanding interrupts
- return this->interrupts.getInterrupt(this->threadContexts[0]);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::processInterrupts(Fault interrupt)
-{
- // Check for interrupts here. For now can copy the code that
- // exists within isa_fullsys_traits.hh. Also assume that thread 0
- // is the one that handles the interrupts.
- // @todo: Possibly consolidate the interrupt checking code.
- // @todo: Allow other threads to handle interrupts.
-
- assert(interrupt != NoFault);
- this->interrupts.updateIntrInfo(this->threadContexts[0]);
-
- DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
- this->trap(interrupt, 0);
-}
-
-#endif // FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::trap(Fault fault, unsigned tid)
-{
- // Pass the thread's TC into the invoke method.
- fault->invoke(this->threadContexts[tid]);
-}
-
-#if !FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::syscall(int64_t callnum, int tid)
-{
- DPRINTF(O3CPU, "[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);
-}
-
-template <class Impl>
-TheISA::IntReg
-AlphaO3CPU<Impl>::getSyscallArg(int i, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- return this->readArchIntReg(AlphaISA::ArgumentReg[i], tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- this->setArchIntReg(AlphaISA::ArgumentReg[i], val, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- TheISA::setSyscallReturn(return_value, this->tcBase(tid));
-}
-#endif
diff --git a/src/cpu/o3/alpha/dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc
deleted file mode 100644
index 97d2f3d08..000000000
--- a/src/cpu/o3/alpha/dyn_inst.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 "cpu/o3/alpha/dyn_inst_impl.hh"
-#include "cpu/o3/alpha/impl.hh"
-
-// Force instantiation of AlphaDynInst for all the implementations that
-// are needed.
-template class AlphaDynInst<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh
deleted file mode 100644
index a6fb7b885..000000000
--- a/src/cpu/o3/alpha/dyn_inst.hh
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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
- */
-
-#ifndef __CPU_O3_ALPHA_DYN_INST_HH__
-#define __CPU_O3_ALPHA_DYN_INST_HH__
-
-#include "arch/isa_traits.hh"
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/inst_seq.hh"
-#include "cpu/o3/alpha/cpu.hh"
-#include "cpu/o3/alpha/impl.hh"
-
-class Packet;
-
-/**
- * Mostly implementation & ISA specific AlphaDynInst. As with most
- * other classes in the new CPU model, it is templated on the Impl to
- * allow for passing in of all types, such as the CPU type and the ISA
- * type. The AlphaDynInst serves as the primary interface to the CPU
- * for instructions that are executing.
- */
-template <class Impl>
-class AlphaDynInst : public BaseDynInst<Impl>
-{
- public:
- /** Typedef for the CPU. */
- typedef typename Impl::O3CPU O3CPU;
-
- /** 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 index type. */
- typedef TheISA::IntReg IntReg;
- typedef TheISA::FloatReg FloatReg;
- typedef TheISA::FloatRegBits FloatRegBits;
- /** Misc register index type. */
- typedef TheISA::MiscReg MiscReg;
-
- enum {
- MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
- MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
- };
-
- public:
- /** BaseDynInst constructor given a binary instruction. */
- AlphaDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a binary instruction. */
- AlphaDynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a static inst pointer. */
- AlphaDynInst(StaticInstPtr &_staticInst);
-
- /** Executes the instruction.*/
- Fault execute();
-
- /** Initiates the access. Only valid for memory operations. */
- Fault initiateAcc();
-
- /** Completes the access. Only valid for memory operations. */
- Fault completeAcc(PacketPtr pkt);
-
- private:
- /** Initializes variables. */
- void initVars();
-
- public:
- /** Reads a miscellaneous register. */
- MiscReg readMiscRegNoEffect(int misc_reg)
- {
- return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- MiscReg readMiscReg(int misc_reg)
- {
- return this->cpu->readMiscReg(misc_reg, this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
- }
-
- /** 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)
- {
- return this->cpu->setMiscReg(misc_reg, val,
- this->threadNumber);
- }
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg 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.
- */
- TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscReg(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
- {
- this->instResult.integer = val;
- return 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 setMiscRegOperand(const StaticInst *si, int idx,
- const MiscReg &val)
- {
- return this->cpu->setMiscReg(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
-#if FULL_SYSTEM
- /** Calls hardware return from error interrupt. */
- Fault hwrei();
- /** Traps to handle specified fault. */
- void trap(Fault fault);
- bool simPalCheck(int palFunc);
-#else
- /** Calls a syscall. */
- void syscall(int64_t callnum);
-#endif
-
- public:
-
- // The register accessor methods provide the index of the
- // instruction's operand (e.g., 0 or 1), not the architectural
- // register index, to simplify the implementation of register
- // renaming. We find the architectural register index by indexing
- // into the instruction's own operand index table. Note that a
- // raw pointer to the StaticInst is provided instead of a
- // ref-counted StaticInstPtr to redice overhead. This is fine as
- // long as these methods don't copy the pointer into any long-term
- // storage (which is pretty hard to imagine they would have reason
- // to do).
-
- uint64_t readIntRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readIntReg(this->_srcRegIdx[idx]);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
- int width)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
- }
-
- /** @todo: Make results into arrays so they can handle multiple dest
- * registers.
- */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
- {
- this->cpu->setIntReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
- int width)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val, int width)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- public:
- /** Calculates EA part of a memory instruction. Currently unused,
- * though it may be useful in the future if we want to split
- * memory operations into EA calculation and memory access parts.
- */
- Fault calcEA()
- {
- return this->staticInst->eaCompInst()->execute(this, this->traceData);
- }
-
- /** Does the memory access part of a memory instruction. Currently unused,
- * though it may be useful in the future if we want to split
- * memory operations into EA calculation and memory access parts.
- */
- Fault memAccess()
- {
- return this->staticInst->memAccInst()->execute(this, this->traceData);
- }
-};
-
-#endif // __CPU_O3_ALPHA_DYN_INST_HH__
-
diff --git a/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh
deleted file mode 100644
index b928ae654..000000000
--- a/src/cpu/o3/alpha/impl.hh
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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
- */
-
-#ifndef __CPU_O3_ALPHA_IMPL_HH__
-#define __CPU_O3_ALPHA_IMPL_HH__
-
-#include "arch/alpha/isa_traits.hh"
-
-#include "cpu/o3/alpha/params.hh"
-#include "cpu/o3/cpu_policy.hh"
-
-
-// Forward declarations.
-template <class Impl>
-class AlphaDynInst;
-
-template <class Impl>
-class AlphaO3CPU;
-
-/** Implementation specific struct that defines several key types to the
- * CPU, the stages within the CPU, the time buffers, and the DynInst.
- * The struct defines the ISA, the CPU policy, the specific DynInst, the
- * specific O3CPU, and all of the structs from the time buffers to do
- * communication.
- * This is one of the key things that must be defined for each hardware
- * specific CPU implementation.
- */
-struct AlphaSimpleImpl
-{
- /** The type of MachInst. */
- typedef TheISA::MachInst MachInst;
-
- /** The CPU policy to be used, which defines all of the CPU stages. */
- typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol;
-
- /** The DynInst type to be used. */
- typedef AlphaDynInst<AlphaSimpleImpl> DynInst;
-
- /** The refcounted DynInst pointer to be used. In most cases this is
- * what should be used, and not DynInst *.
- */
- typedef RefCountingPtr<DynInst> DynInstPtr;
-
- /** The O3CPU type to be used. */
- typedef AlphaO3CPU<AlphaSimpleImpl> O3CPU;
-
- /** Same typedef, but for CPUType. BaseDynInst may not always use
- * an O3 CPU, so it's clearer to call it CPUType instead in that
- * case.
- */
- typedef O3CPU CPUType;
-
- /** The Params to be passed to each stage. */
- typedef AlphaSimpleParams Params;
-
- enum {
- MaxWidth = 8,
- MaxThreads = 4
- };
-};
-
-/** The O3Impl to be used. */
-typedef AlphaSimpleImpl O3CPUImpl;
-
-#endif // __CPU_O3_ALPHA_IMPL_HH__
diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc
index 0979c5c8f..510109d8a 100644
--- a/src/cpu/o3/base_dyn_inst.cc
+++ b/src/cpu/o3/base_dyn_inst.cc
@@ -29,11 +29,8 @@
*/
#include "cpu/base_dyn_inst_impl.hh"
+#include "cpu/o3/cpu.hh"
#include "cpu/o3/isa_specific.hh"
// Explicit instantiation
template class BaseDynInst<O3CPUImpl>;
-
-template <>
-int
-BaseDynInst<O3CPUImpl>::instcount = 0;
diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh
index 3c4c8e478..b32d2bd23 100644
--- a/src/cpu/o3/bpred_unit.hh
+++ b/src/cpu/o3/bpred_unit.hh
@@ -43,6 +43,8 @@
#include <list>
+class DerivO3CPUParams;
+
/**
* Basically a wrapper class to hold both the branch predictor
* and the BTB.
@@ -51,7 +53,6 @@ template<class Impl>
class BPredUnit
{
private:
- typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
enum PredType {
@@ -61,12 +62,16 @@ class BPredUnit
PredType predictor;
+ const std::string _name;
+
public:
/**
* @param params The params object, that has the size of the BP and BTB.
*/
- BPredUnit(Params *params);
+ BPredUnit(DerivO3CPUParams *params);
+
+ const std::string &name() const { return _name; }
/**
* Registers statistics.
@@ -236,21 +241,21 @@ class BPredUnit
ReturnAddrStack RAS[Impl::MaxThreads];
/** Stat for number of BP lookups. */
- Stats::Scalar<> lookups;
+ Stats::Scalar lookups;
/** Stat for number of conditional branches predicted. */
- Stats::Scalar<> condPredicted;
+ Stats::Scalar condPredicted;
/** Stat for number of conditional branches predicted incorrectly. */
- Stats::Scalar<> condIncorrect;
+ Stats::Scalar condIncorrect;
/** Stat for number of BTB lookups. */
- Stats::Scalar<> BTBLookups;
+ Stats::Scalar BTBLookups;
/** Stat for number of BTB hits. */
- Stats::Scalar<> BTBHits;
+ Stats::Scalar BTBHits;
/** Stat for number of times the BTB is correct. */
- Stats::Scalar<> BTBCorrect;
+ Stats::Scalar BTBCorrect;
/** Stat for number of times the RAS is used to get a target. */
- Stats::Scalar<> usedRAS;
+ Stats::Scalar usedRAS;
/** Stat for number of times the RAS is incorrect. */
- Stats::Scalar<> RASIncorrect;
+ Stats::Scalar RASIncorrect;
};
#endif // __CPU_O3_BPRED_UNIT_HH__
diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh
index 84c50b4da..2fa59280d 100644
--- a/src/cpu/o3/bpred_unit_impl.hh
+++ b/src/cpu/o3/bpred_unit_impl.hh
@@ -34,11 +34,14 @@
#include "base/traceflags.hh"
#include "cpu/o3/bpred_unit.hh"
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
-BPredUnit<Impl>::BPredUnit(Params *params)
- : BTB(params->BTBEntries,
- params->BTBTagSize,
- params->instShiftAmt)
+BPredUnit<Impl>::BPredUnit(DerivO3CPUParams *params)
+ : _name(params->name + ".BPredUnit"),
+ BTB(params->BTBEntries,
+ params->BTBTagSize,
+ params->instShiftAmt)
{
// Setup the selected predictor.
if (params->predType == "local") {
@@ -71,43 +74,43 @@ void
BPredUnit<Impl>::regStats()
{
lookups
- .name(name() + ".BPredUnit.lookups")
+ .name(name() + ".lookups")
.desc("Number of BP lookups")
;
condPredicted
- .name(name() + ".BPredUnit.condPredicted")
+ .name(name() + ".condPredicted")
.desc("Number of conditional branches predicted")
;
condIncorrect
- .name(name() + ".BPredUnit.condIncorrect")
+ .name(name() + ".condIncorrect")
.desc("Number of conditional branches incorrect")
;
BTBLookups
- .name(name() + ".BPredUnit.BTBLookups")
+ .name(name() + ".BTBLookups")
.desc("Number of BTB lookups")
;
BTBHits
- .name(name() + ".BPredUnit.BTBHits")
+ .name(name() + ".BTBHits")
.desc("Number of BTB hits")
;
BTBCorrect
- .name(name() + ".BPredUnit.BTBCorrect")
+ .name(name() + ".BTBCorrect")
.desc("Number of correct BTB predictions (this stat may not "
"work properly.")
;
usedRAS
- .name(name() + ".BPredUnit.usedRAS")
+ .name(name() + ".usedRAS")
.desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
- .name(name() + ".BPredUnit.RASInCorrect")
+ .name(name() + ".RASInCorrect")
.desc("Number of incorrect RAS predictions.")
;
}
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index 80e42fa8b..f21c14569 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -37,6 +37,8 @@
#include "cpu/exetrace.hh"
#include "cpu/inst_seq.hh"
+class DerivO3CPUParams;
+
template <class>
class O3ThreadState;
@@ -69,7 +71,6 @@ class DefaultCommit
// Typedefs from the Impl.
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::Params Params;
typedef typename Impl::CPUPol CPUPol;
typedef typename CPUPol::RenameMap RenameMap;
@@ -136,7 +137,7 @@ class DefaultCommit
public:
/** Construct a DefaultCommit with the given parameters. */
- DefaultCommit(O3CPU *_cpu, Params *params);
+ DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of the DefaultCommit. */
std::string name() const;
@@ -451,40 +452,40 @@ class DefaultCommit
void updateComInstStats(DynInstPtr &inst);
/** Stat for the total number of committed instructions. */
- Stats::Scalar<> commitCommittedInsts;
+ Stats::Scalar commitCommittedInsts;
/** Stat for the total number of squashed instructions discarded by commit.
*/
- Stats::Scalar<> commitSquashedInsts;
+ Stats::Scalar commitSquashedInsts;
/** Stat for the total number of times commit is told to squash.
* @todo: Actually increment this stat.
*/
- Stats::Scalar<> commitSquashEvents;
+ Stats::Scalar commitSquashEvents;
/** Stat for the total number of times commit has had to stall due to a non-
* speculative instruction reaching the head of the ROB.
*/
- Stats::Scalar<> commitNonSpecStalls;
+ Stats::Scalar commitNonSpecStalls;
/** Stat for the total number of branch mispredicts that caused a squash. */
- Stats::Scalar<> branchMispredicts;
+ Stats::Scalar branchMispredicts;
/** Distribution of the number of committed instructions each cycle. */
- Stats::Distribution<> numCommittedDist;
+ Stats::Distribution numCommittedDist;
/** Total number of instructions committed. */
- Stats::Vector<> statComInst;
+ Stats::Vector statComInst;
/** Total number of software prefetches committed. */
- Stats::Vector<> statComSwp;
+ Stats::Vector statComSwp;
/** Stat for the total number of committed memory references. */
- Stats::Vector<> statComRefs;
+ Stats::Vector statComRefs;
/** Stat for the total number of committed loads. */
- Stats::Vector<> statComLoads;
+ Stats::Vector statComLoads;
/** Total number of committed memory barriers. */
- Stats::Vector<> statComMembars;
+ Stats::Vector statComMembars;
/** Total number of committed branches. */
- Stats::Vector<> statComBranches;
+ Stats::Vector statComBranches;
/** Number of cycles where the commit bandwidth limit is reached. */
- Stats::Scalar<> commitEligibleSamples;
+ Stats::Scalar commitEligibleSamples;
/** Number of instructions not committed due to bandwidth limits. */
- Stats::Vector<> commitEligible;
+ Stats::Vector commitEligible;
};
#endif // __CPU_O3_COMMIT_HH__
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index ee0f2bb59..7cd88b49b 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -36,6 +36,7 @@
#include <string>
#include "arch/utility.hh"
+#include "base/cp_annotate.hh"
#include "base/loader/symtab.hh"
#include "base/timebuf.hh"
#include "cpu/exetrace.hh"
@@ -46,12 +47,14 @@
#include "cpu/checker/cpu.hh"
#endif
+#include "params/DerivO3CPU.hh"
+
template <class Impl>
DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
unsigned _tid)
- : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
+ : Event(CPU_Tick_Pri), commit(_commit), tid(_tid)
{
- this->setFlags(Event::AutoDelete);
+ this->setFlags(AutoDelete);
}
template <class Impl>
@@ -71,7 +74,7 @@ DefaultCommit<Impl>::TrapEvent::description() const
}
template <class Impl>
-DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params)
+DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
squashCounter(0),
iewToCommitDelay(params->iewToCommitDelay),
@@ -80,7 +83,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params)
fetchToCommitDelay(params->commitToFetchDelay),
renameWidth(params->renameWidth),
commitWidth(params->commitWidth),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
drainPending(false),
switchedOut(false),
trapLatency(params->trapLatency)
@@ -460,7 +463,7 @@ DefaultCommit<Impl>::generateTrapEvent(unsigned tid)
TrapEvent *trap = new TrapEvent(this, tid);
- trap->schedule(curTick + trapLatency);
+ cpu->schedule(trap, curTick + trapLatency);
trapInFlight[tid] = true;
}
@@ -663,7 +666,7 @@ DefaultCommit<Impl>::handleInterrupt()
DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
}
} else if (commitStatus[0] != TrapPending &&
- cpu->check_interrupts(cpu->tcBase(0)) &&
+ cpu->checkInterrupts(cpu->tcBase(0)) &&
!trapSquash[0] &&
!tcSquash[0]) {
// Process interrupts if interrupts are enabled, not in PAL
@@ -693,7 +696,7 @@ DefaultCommit<Impl>::commit()
// Check for any interrupt, and start processing it. Or if we
// have an outstanding interrupt and are at a point when it is
// valid to take an interrupt, process it.
- if (cpu->check_interrupts(cpu->tcBase(0))) {
+ if (cpu->checkInterrupts(cpu->tcBase(0))) {
handleInterrupt();
}
#endif // FULL_SYSTEM
@@ -812,7 +815,7 @@ DefaultCommit<Impl>::commit()
// @todo: Make this handle multi-cycle communication between
// commit and IEW.
if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
- !iewStage->hasStoresToWB() && !committedStores[tid]) {
+ !iewStage->hasStoresToWB(tid) && !committedStores[tid]) {
checkEmptyROB[tid] = false;
toIEW->commitInfo[tid].usedROB = true;
toIEW->commitInfo[tid].emptyROB = true;
@@ -966,7 +969,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
"instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
head_inst->seqNum, head_inst->readPC());
- if (inst_num > 0 || iewStage->hasStoresToWB()) {
+ if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
DPRINTF(Commit, "Waiting for all stores to writeback.\n");
return false;
}
@@ -981,7 +984,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
return false;
} else if (head_inst->isLoad()) {
- if (inst_num > 0 || iewStage->hasStoresToWB()) {
+ if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
DPRINTF(Commit, "Waiting for all stores to writeback.\n");
return false;
}
@@ -1036,7 +1039,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
head_inst->seqNum, head_inst->readPC());
- if (iewStage->hasStoresToWB() || inst_num > 0) {
+ if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
return false;
}
@@ -1095,6 +1098,12 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
if (node)
thread[tid]->profileNode = node;
}
+ if (CPA::available()) {
+ if (head_inst->isControl()) {
+ ThreadContext *tc = thread[tid]->getTC();
+ CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC());
+ }
+ }
#endif
if (head_inst->traceData) {
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index c75a08213..1d7fb97c0 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -37,6 +37,7 @@
#include "cpu/thread_context.hh"
#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/cpu.hh"
+#include "cpu/o3/thread_context.hh"
#include "enums/MemoryMode.hh"
#include "sim/core.hh"
#include "sim/stat_control.hh"
@@ -52,10 +53,16 @@
#include "cpu/checker/cpu.hh"
#endif
+#if THE_ISA == ALPHA_ISA
+#include "arch/alpha/osfpal.hh"
+#endif
+
+class BaseCPUParams;
+
using namespace TheISA;
-BaseO3CPU::BaseO3CPU(Params *params)
- : BaseCPU(params), cpu_id(0)
+BaseO3CPU::BaseO3CPU(BaseCPUParams *params)
+ : BaseCPU(params)
{
}
@@ -67,7 +74,7 @@ BaseO3CPU::regStats()
template <class Impl>
FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
- : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+ : Event(CPU_Tick_Pri), cpu(c)
{
}
@@ -87,7 +94,7 @@ FullO3CPU<Impl>::TickEvent::description() const
template <class Impl>
FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent()
- : Event(&mainEventQueue, CPU_Switch_Pri)
+ : Event(CPU_Switch_Pri)
{
}
@@ -116,7 +123,7 @@ FullO3CPU<Impl>::ActivateThreadEvent::description() const
template <class Impl>
FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent()
- : Event(&mainEventQueue, CPU_Tick_Pri), tid(0), remove(false), cpu(NULL)
+ : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL)
{
}
@@ -147,31 +154,34 @@ FullO3CPU<Impl>::DeallocateContextEvent::description() const
}
template <class Impl>
-FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
+FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
: BaseO3CPU(params),
itb(params->itb),
dtb(params->dtb),
tickEvent(this),
+#ifndef NDEBUG
+ instcount(0),
+#endif
removeInstsThisCycle(false),
- fetch(o3_cpu, params),
- decode(o3_cpu, params),
- rename(o3_cpu, params),
- iew(o3_cpu, params),
- commit(o3_cpu, params),
+ fetch(this, params),
+ decode(this, params),
+ rename(this, params),
+ iew(this, params),
+ commit(this, params),
- regFile(o3_cpu, params->numPhysIntRegs,
+ regFile(this, params->numPhysIntRegs,
params->numPhysFloatRegs),
- freeList(params->numberOfThreads,
+ freeList(params->numThreads,
TheISA::NumIntRegs, params->numPhysIntRegs,
TheISA::NumFloatRegs, params->numPhysFloatRegs),
- rob(o3_cpu,
+ rob(this,
params->numROBEntries, params->squashWidth,
params->smtROBPolicy, params->smtROBThreshold,
- params->numberOfThreads),
+ params->numThreads),
- scoreboard(params->numberOfThreads,
+ scoreboard(params->numThreads,
TheISA::NumIntRegs, params->numPhysIntRegs,
TheISA::NumFloatRegs, params->numPhysFloatRegs,
TheISA::NumMiscRegs * number_of_threads,
@@ -182,7 +192,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
decodeQueue(params->backComSize, params->forwardComSize),
renameQueue(params->backComSize, params->forwardComSize),
iewQueue(params->backComSize, params->forwardComSize),
- activityRec(NumStages,
+ activityRec(name(), NumStages,
params->backComSize + params->forwardComSize,
params->activity),
@@ -192,7 +202,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
physmem(system->physmem),
#endif // FULL_SYSTEM
drainCount(0),
- deferRegistration(params->deferRegistration),
+ deferRegistration(params->defer_registration),
numThreads(number_of_threads)
{
if (!deferRegistration) {
@@ -336,6 +346,78 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
//}
contextSwitch = false;
+ DPRINTF(O3CPU, "Creating O3CPU object.\n");
+
+ // Setup any thread state.
+ this->thread.resize(this->numThreads);
+
+ for (int i = 0; i < this->numThreads; ++i) {
+#if FULL_SYSTEM
+ // SMT is not supported in FS mode yet.
+ assert(this->numThreads == 1);
+ this->thread[i] = new Thread(this, 0);
+ this->thread[i]->setStatus(ThreadContext::Suspended);
+#else
+ if (i < params->workload.size()) {
+ DPRINTF(O3CPU, "Workload[%i] process is %#x",
+ i, this->thread[i]);
+ this->thread[i] = new typename FullO3CPU<Impl>::Thread(
+ (typename Impl::O3CPU *)(this),
+ i, params->workload[i], i);
+
+ this->thread[i]->setStatus(ThreadContext::Suspended);
+
+ //usedTids[i] = true;
+ //threadMap[i] = i;
+ } else {
+ //Allocate Empty thread so M5 can use later
+ //when scheduling threads to CPU
+ Process* dummy_proc = NULL;
+
+ this->thread[i] = new typename FullO3CPU<Impl>::Thread(
+ (typename Impl::O3CPU *)(this),
+ i, dummy_proc, i);
+ //usedTids[i] = false;
+ }
+#endif // !FULL_SYSTEM
+
+ ThreadContext *tc;
+
+ // Setup the TC that will serve as the interface to the threads/CPU.
+ O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
+
+ tc = o3_tc;
+
+ // If we're using a checker, then the TC should be the
+ // CheckerThreadContext.
+#if USE_CHECKER
+ if (params->checker) {
+ tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
+ o3_tc, this->checker);
+ }
+#endif
+
+ o3_tc->cpu = (typename Impl::O3CPU *)(this);
+ assert(o3_tc->cpu);
+ o3_tc->thread = this->thread[i];
+
+#if FULL_SYSTEM
+ // Setup quiesce event.
+ this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc);
+#endif
+ // Give the thread the TC.
+ this->thread[i]->tc = tc;
+
+ // Add the TC to the CPU's list of TC's.
+ this->threadContexts.push_back(tc);
+ }
+
+ for (int i=0; i < this->numThreads; i++) {
+ this->thread[i]->setFuncExeInst(0);
+ }
+
+ lockAddr = 0;
+ lockFlag = false;
}
template <class Impl>
@@ -345,7 +427,7 @@ FullO3CPU<Impl>::~FullO3CPU()
template <class Impl>
void
-FullO3CPU<Impl>::fullCPURegStats()
+FullO3CPU<Impl>::regStats()
{
BaseO3CPU::regStats();
@@ -399,6 +481,11 @@ FullO3CPU<Impl>::fullCPURegStats()
.precision(6);
totalIpc = totalCommittedInsts / numCycles;
+ this->fetch.regStats();
+ this->decode.regStats();
+ this->rename.regStats();
+ this->iew.regStats();
+ this->commit.regStats();
}
template <class Impl>
@@ -463,7 +550,7 @@ FullO3CPU<Impl>::tick()
lastRunningCycle = curTick;
timesIdled++;
} else {
- tickEvent.schedule(nextCycle(curTick + ticks(1)));
+ schedule(tickEvent, nextCycle(curTick + ticks(1)));
DPRINTF(O3CPU, "Scheduling next tick!\n");
}
}
@@ -471,16 +558,13 @@ FullO3CPU<Impl>::tick()
#if !FULL_SYSTEM
updateThreadPriority();
#endif
-
}
template <class Impl>
void
FullO3CPU<Impl>::init()
{
- if (!deferRegistration) {
- registerThreadContexts();
- }
+ BaseCPU::init();
// Set inSyscall so that the CPU doesn't squash when initially
// setting up registers.
@@ -499,7 +583,7 @@ FullO3CPU<Impl>::init()
}
#if FULL_SYSTEM
- TheISA::initCPU(src_tc, src_tc->readCpuId());
+ TheISA::initCPU(src_tc, src_tc->contextId());
#endif
}
@@ -602,7 +686,7 @@ FullO3CPU<Impl>::suspendContext(int tid)
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
bool deallocated = deallocateContext(tid, false, 1);
// If this was the last thread then unschedule the tick event.
- if (activeThreads.size() == 1 && !deallocated ||
+ if ((activeThreads.size() == 1 && !deallocated) ||
activeThreads.size() == 0)
unscheduleTickEvent();
_status = Idle;
@@ -782,18 +866,116 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
#if FULL_SYSTEM
template <class Impl>
+Fault
+FullO3CPU<Impl>::hwrei(unsigned tid)
+{
+#if THE_ISA == ALPHA_ISA
+ // Need to clear the lock flag upon returning from an interrupt.
+ this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
+
+ this->thread[tid]->kernelStats->hwrei();
+
+ // FIXME: XXX check for interrupts? XXX
+#endif
+ return NoFault;
+}
+
+template <class Impl>
+bool
+FullO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid)
+{
+#if THE_ISA == ALPHA_ISA
+ if (this->thread[tid]->kernelStats)
+ this->thread[tid]->kernelStats->callpal(palFunc,
+ this->threadContexts[tid]);
+
+ switch (palFunc) {
+ case PAL::halt:
+ halt();
+ if (--System::numSystemsRunning == 0)
+ exitSimLoop("all cpus halted");
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (this->system->breakpoint())
+ return false;
+ break;
+ }
+#endif
+ return true;
+}
+
+template <class Impl>
+Fault
+FullO3CPU<Impl>::getInterrupts()
+{
+ // Check if there are any outstanding interrupts
+ return this->interrupts->getInterrupt(this->threadContexts[0]);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::processInterrupts(Fault interrupt)
+{
+ // Check for interrupts here. For now can copy the code that
+ // exists within isa_fullsys_traits.hh. Also assume that thread 0
+ // is the one that handles the interrupts.
+ // @todo: Possibly consolidate the interrupt checking code.
+ // @todo: Allow other threads to handle interrupts.
+
+ assert(interrupt != NoFault);
+ this->interrupts->updateIntrInfo(this->threadContexts[0]);
+
+ DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
+ this->trap(interrupt, 0);
+}
+
+template <class Impl>
void
FullO3CPU<Impl>::updateMemPorts()
{
// Update all ThreadContext's memory ports (Functional/Virtual
// Ports)
for (int i = 0; i < thread.size(); ++i)
- thread[i]->connectMemPorts();
+ thread[i]->connectMemPorts(thread[i]->getTC());
}
#endif
template <class Impl>
void
+FullO3CPU<Impl>::trap(Fault fault, unsigned tid)
+{
+ // Pass the thread's TC into the invoke method.
+ fault->invoke(this->threadContexts[tid]);
+}
+
+#if !FULL_SYSTEM
+
+template <class Impl>
+void
+FullO3CPU<Impl>::syscall(int64_t callnum, int tid)
+{
+ DPRINTF(O3CPU, "[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);
+}
+
+#endif
+
+template <class Impl>
+void
FullO3CPU<Impl>::serialize(std::ostream &os)
{
SimObject::State so_state = SimObject::getState();
@@ -891,7 +1073,7 @@ FullO3CPU<Impl>::resume()
#endif
if (!tickEvent.scheduled())
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
_status = Running;
}
@@ -984,11 +1166,41 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
ThreadContext *tc = threadContexts[i];
if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
}
}
if (!tickEvent.scheduled())
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
+}
+
+template <class Impl>
+TheISA::MiscReg
+FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
+{
+ return this->regFile.readMiscRegNoEffect(misc_reg, tid);
+}
+
+template <class Impl>
+TheISA::MiscReg
+FullO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
+{
+ return this->regFile.readMiscReg(misc_reg, tid);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg,
+ const TheISA::MiscReg &val, unsigned tid)
+{
+ this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setMiscReg(int misc_reg,
+ const TheISA::MiscReg &val, unsigned tid)
+{
+ this->regFile.setMiscReg(misc_reg, val, tid);
}
template <class Impl>
@@ -1210,6 +1422,14 @@ FullO3CPU<Impl>::setNextMicroPC(Addr new_PC,unsigned tid)
}
template <class Impl>
+void
+FullO3CPU<Impl>::squashFromTC(unsigned tid)
+{
+ this->thread[tid]->inSyscall = true;
+ this->commit.generateTCEvent(tid);
+}
+
+template <class Impl>
typename FullO3CPU<Impl>::ListIt
FullO3CPU<Impl>::addInst(DynInstPtr &inst)
{
@@ -1419,9 +1639,24 @@ FullO3CPU<Impl>::wakeCPU()
idleCycles += tickToCycles((curTick - 1) - lastRunningCycle);
numCycles += tickToCycles((curTick - 1) - lastRunningCycle);
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
}
+#if FULL_SYSTEM
+template <class Impl>
+void
+FullO3CPU<Impl>::wakeup()
+{
+ if (this->thread[0]->status() != ThreadContext::Suspended)
+ return;
+
+ this->wakeCPU();
+
+ DPRINTF(Quiesce, "Suspended Processor woken\n");
+ this->threadContexts[0]->activate();
+}
+#endif
+
template <class Impl>
int
FullO3CPU<Impl>::getFreeTid()
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index 61d7dcf22..942970f5f 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -53,6 +53,8 @@
//#include "cpu/o3/thread_context.hh"
#include "sim/process.hh"
+#include "params/DerivO3CPU.hh"
+
template <class>
class Checker;
class ThreadContext;
@@ -63,24 +65,15 @@ class Checkpoint;
class MemObject;
class Process;
+class BaseCPUParams;
+
class BaseO3CPU : public BaseCPU
{
//Stuff that's pretty ISA independent will go here.
public:
- typedef BaseCPU::Params Params;
-
- BaseO3CPU(Params *params);
+ BaseO3CPU(BaseCPUParams *params);
void regStats();
-
- /** Sets this CPU's ID. */
- void setCpuId(int id) { cpu_id = id; }
-
- /** Reads this CPU's ID. */
- int readCpuId() { return cpu_id; }
-
- protected:
- int cpu_id;
};
/**
@@ -96,8 +89,8 @@ class FullO3CPU : public BaseO3CPU
typedef typename Impl::CPUPol CPUPolicy;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
+ typedef O3ThreadState<Impl> ImplState;
typedef O3ThreadState<Impl> Thread;
typedef typename std::list<DynInstPtr>::iterator ListIt;
@@ -146,9 +139,9 @@ class FullO3CPU : public BaseO3CPU
void scheduleTickEvent(int delay)
{
if (tickEvent.squashed())
- tickEvent.reschedule(nextCycle(curTick + ticks(delay)));
+ reschedule(tickEvent, nextCycle(curTick + ticks(delay)));
else if (!tickEvent.scheduled())
- tickEvent.schedule(nextCycle(curTick + ticks(delay)));
+ schedule(tickEvent, nextCycle(curTick + ticks(delay)));
}
/** Unschedule tick event, regardless of its current state. */
@@ -186,11 +179,11 @@ class FullO3CPU : public BaseO3CPU
{
// Schedule thread to activate, regardless of its current state.
if (activateThreadEvent[tid].squashed())
- activateThreadEvent[tid].
- reschedule(nextCycle(curTick + ticks(delay)));
+ reschedule(activateThreadEvent[tid],
+ nextCycle(curTick + ticks(delay)));
else if (!activateThreadEvent[tid].scheduled())
- activateThreadEvent[tid].
- schedule(nextCycle(curTick + ticks(delay)));
+ schedule(activateThreadEvent[tid],
+ nextCycle(curTick + ticks(delay)));
}
/** Unschedule actiavte thread event, regardless of its current state. */
@@ -237,11 +230,11 @@ class FullO3CPU : public BaseO3CPU
{
// Schedule thread to activate, regardless of its current state.
if (deallocateContextEvent[tid].squashed())
- deallocateContextEvent[tid].
- reschedule(nextCycle(curTick + ticks(delay)));
+ reschedule(deallocateContextEvent[tid],
+ nextCycle(curTick + ticks(delay)));
else if (!deallocateContextEvent[tid].scheduled())
- deallocateContextEvent[tid].
- schedule(nextCycle(curTick + ticks(delay)));
+ schedule(deallocateContextEvent[tid],
+ nextCycle(curTick + ticks(delay)));
}
/** Unschedule thread deallocation in CPU */
@@ -256,12 +249,12 @@ class FullO3CPU : public BaseO3CPU
public:
/** Constructs a CPU with the given parameters. */
- FullO3CPU(O3CPU *o3_cpu, Params *params);
+ FullO3CPU(DerivO3CPUParams *params);
/** Destructor. */
~FullO3CPU();
/** Registers statistics. */
- void fullCPURegStats();
+ void regStats();
void demapPage(Addr vaddr, uint64_t asn)
{
@@ -279,24 +272,6 @@ class FullO3CPU : public BaseO3CPU
this->dtb->demapPage(vaddr, asn);
}
- /** Translates instruction requestion. */
- Fault translateInstReq(RequestPtr &req, Thread *thread)
- {
- return this->itb->translate(req, thread->getTC());
- }
-
- /** Translates data read request. */
- Fault translateDataReadReq(RequestPtr &req, Thread *thread)
- {
- return this->dtb->translate(req, thread->getTC(), false);
- }
-
- /** Translates data write request. */
- Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
- {
- return this->dtb->translate(req, thread->getTC(), true);
- }
-
/** Returns a specific port. */
Port *getPort(const std::string &if_name, int idx);
@@ -367,12 +342,12 @@ class FullO3CPU : public BaseO3CPU
virtual void unserialize(Checkpoint *cp, const std::string &section);
public:
- /** Executes a syscall on this cycle.
- * ---------------------------------------
- * Note: this is a virtual function. CPU-Specific
- * functionality defined in derived classes
+#if !FULL_SYSTEM
+ /** Executes a syscall.
+ * @todo: Determine if this needs to be virtual.
*/
- virtual void syscall(int tid) { panic("Unimplemented!"); }
+ void syscall(int64_t callnum, int tid);
+#endif
/** Starts draining the CPU's pipeline of all instructions in
* order to stop all memory accesses. */
@@ -394,7 +369,24 @@ class FullO3CPU : public BaseO3CPU
InstSeqNum getAndIncrementInstSeq()
{ return globalSeqNum++; }
+ /** Traps to handle given fault. */
+ void trap(Fault fault, unsigned tid);
+
#if FULL_SYSTEM
+ /** HW return from error interrupt. */
+ Fault hwrei(unsigned tid);
+
+ bool simPalCheck(int palFunc, unsigned tid);
+
+ /** Returns the Fault for any valid interrupt. */
+ Fault getInterrupts();
+
+ /** Processes any an interrupt fault. */
+ void processInterrupts(Fault interrupt);
+
+ /** Halts the CPU. */
+ void halt() { panic("Halt not implemented!\n"); }
+
/** Update the Virt and Phys ports of all ThreadContexts to
* reflect change in memory connections. */
void updateMemPorts();
@@ -424,6 +416,24 @@ class FullO3CPU : public BaseO3CPU
#endif
/** Register accessors. Index refers to the physical register index. */
+
+ /** Reads a miscellaneous register. */
+ TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
+
+ /** Reads a misc. register, including any side effects the read
+ * might have as defined by the architecture.
+ */
+ TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
+
+ /** Sets a miscellaneous register. */
+ void setMiscRegNoEffect(int misc_reg, const TheISA::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 TheISA::MiscReg &val,
+ unsigned tid);
+
uint64_t readIntReg(int reg_idx);
TheISA::FloatReg readFloatReg(int reg_idx);
@@ -495,6 +505,12 @@ class FullO3CPU : public BaseO3CPU
/** Sets the commit next micro PC of a specific thread. */
void setNextMicroPC(Addr val, unsigned tid);
+ /** Initiates a squash of all in-flight instructions for a given
+ * thread. The source of the squash is an external update of
+ * state through the TC.
+ */
+ void squashFromTC(unsigned tid);
+
/** Function to add instruction onto the head of the list of the
* instructions. Used when new instructions are fetched.
*/
@@ -528,6 +544,11 @@ class FullO3CPU : public BaseO3CPU
void dumpInsts();
public:
+#ifndef NDEBUG
+ /** Count of total number of dynamic instructions in flight. */
+ int instcount;
+#endif
+
/** List of all the instructions in flight. */
std::list<DynInstPtr> instList;
@@ -648,6 +669,10 @@ class FullO3CPU : public BaseO3CPU
/** Wakes the CPU, rescheduling the CPU if it's not already active. */
void wakeCPU();
+#if FULL_SYSTEM
+ virtual void wakeup();
+#endif
+
/** Gets a free thread id. Use if thread ids change across system. */
int getFreeTid();
@@ -710,14 +735,33 @@ class FullO3CPU : public BaseO3CPU
/** Available thread ids in the cpu*/
std::vector<unsigned> tids;
+ /** CPU read function, forwards read to LSQ. */
+ template <class T>
+ Fault read(RequestPtr &req, T &data, int load_idx)
+ {
+ return this->iew.ldstQueue.read(req, data, load_idx);
+ }
+
+ /** CPU write function, forwards write to LSQ. */
+ template <class T>
+ Fault write(RequestPtr &req, T &data, int store_idx)
+ {
+ return this->iew.ldstQueue.write(req, data, store_idx);
+ }
+
+ Addr lockAddr;
+
+ /** Temporary fix for the lock flag, works in the UP case. */
+ bool lockFlag;
+
/** Stat for total number of times the CPU is descheduled. */
- Stats::Scalar<> timesIdled;
+ Stats::Scalar timesIdled;
/** Stat for total number of cycles the CPU spends descheduled. */
- Stats::Scalar<> idleCycles;
+ Stats::Scalar idleCycles;
/** Stat for the number of committed instructions per thread. */
- Stats::Vector<> committedInsts;
+ Stats::Vector committedInsts;
/** Stat for the total number of committed instructions. */
- Stats::Scalar<> totalCommittedInsts;
+ Stats::Scalar totalCommittedInsts;
/** Stat for the CPI per thread. */
Stats::Formula cpi;
/** Stat for the total CPI. */
diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/cpu_builder.cc
index 6d61501ac..77d7091ad 100644
--- a/src/cpu/o3/alpha/thread_context.hh
+++ b/src/cpu/o3/cpu_builder.cc
@@ -28,49 +28,51 @@
* Authors: Kevin Lim
*/
-#include "arch/alpha/types.hh"
-#include "cpu/o3/thread_context.hh"
+#include <string>
-template <class Impl>
-class AlphaTC : public O3ThreadContext<Impl>
+#include "config/full_system.hh"
+#include "config/use_checker.hh"
+#include "cpu/o3/cpu.hh"
+#include "cpu/o3/impl.hh"
+#include "params/DerivO3CPU.hh"
+
+class DerivO3CPU : public FullO3CPU<O3CPUImpl>
{
public:
+ DerivO3CPU(DerivO3CPUParams *p)
+ : FullO3CPU<O3CPUImpl>(p)
+ { }
+};
+
+DerivO3CPU *
+DerivO3CPUParams::create()
+{
#if FULL_SYSTEM
- /** Returns pointer to the quiesce event. */
- virtual EndQuiesceEvent *getQuiesceEvent()
- {
- return this->thread->quiesceEvent;
- }
-#endif
+ // Full-system only supports a single thread for the moment.
+ int actual_num_threads = 1;
+#else
+ // In non-full-system mode, we infer the number of threads from
+ // the workload if it's not explicitly specified.
+ int actual_num_threads =
+ (numThreads >= workload.size()) ? numThreads : workload.size();
- virtual uint64_t readNextNPC()
- {
- return this->readNextPC() + sizeof(TheISA::MachInst);
+ if (workload.size() == 0) {
+ fatal("Must specify at least one workload!");
}
+#endif
- virtual void setNextNPC(uint64_t val)
- {
- panic("Alpha has no NextNPC!");
- }
+ numThreads = actual_num_threads;
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- { panic("Not supported on Alpha!"); }
+ // Default smtFetchPolicy to "RoundRobin", if necessary.
+ std::string round_robin_policy = "RoundRobin";
+ std::string single_thread = "SingleThread";
+ if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
+ smtFetchPolicy = round_robin_policy;
+ else
+ smtFetchPolicy = smtFetchPolicy;
- /** 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();
+ instShiftAmt = 2;
- // If there are still threads executing in the system
- if (this->cpu->numActiveThreads())
- return 0; // don't exit simulation
- else
- return 1; // exit simulation
- }
-};
+ return new DerivO3CPU(this);
+}
diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh
index 32a0adcf1..c06c9a201 100644
--- a/src/cpu/o3/cpu_policy.hh
+++ b/src/cpu/o3/cpu_policy.hh
@@ -65,7 +65,7 @@ struct SimpleCPUPolicy
/** Typedef for the branch prediction unit (which includes the BP,
* RAS, and BTB).
*/
- typedef BPredUnit<Impl> BPredUnit;
+ typedef ::BPredUnit<Impl> BPredUnit;
/** Typedef for the register file. Most classes assume a unified
* physical register file.
*/
@@ -75,15 +75,15 @@ struct SimpleCPUPolicy
/** Typedef for the rename map. */
typedef SimpleRenameMap RenameMap;
/** Typedef for the ROB. */
- typedef ROB<Impl> ROB;
+ typedef ::ROB<Impl> ROB;
/** Typedef for the instruction queue/scheduler. */
typedef InstructionQueue<Impl> IQ;
/** Typedef for the memory dependence unit. */
- typedef MemDepUnit<StoreSet, Impl> MemDepUnit;
+ typedef ::MemDepUnit<StoreSet, Impl> MemDepUnit;
/** Typedef for the LSQ. */
- typedef LSQ<Impl> LSQ;
+ typedef ::LSQ<Impl> LSQ;
/** Typedef for the thread-specific LSQ units. */
- typedef LSQUnit<Impl> LSQUnit;
+ typedef ::LSQUnit<Impl> LSQUnit;
/** Typedef for fetch. */
typedef DefaultFetch<Impl> Fetch;
@@ -109,7 +109,7 @@ struct SimpleCPUPolicy
typedef DefaultIEWDefaultCommit<Impl> IEWStruct;
/** The struct for communication within the IEW stage. */
- typedef IssueStruct<Impl> IssueStruct;
+ typedef ::IssueStruct<Impl> IssueStruct;
/** The struct for all backwards communication. */
typedef TimeBufStruct<Impl> TimeStruct;
diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh
index 3e82033ca..294b5b623 100644
--- a/src/cpu/o3/decode.hh
+++ b/src/cpu/o3/decode.hh
@@ -36,6 +36,8 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
+class DerivO3CPUParams;
+
/**
* DefaultDecode class handles both single threaded and SMT
* decode. Its width is specified by the parameters; each cycles it
@@ -50,7 +52,6 @@ class DefaultDecode
// Typedefs from the Impl.
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::Params Params;
typedef typename Impl::CPUPol CPUPol;
// Typedefs from the CPU policy.
@@ -86,7 +87,7 @@ class DefaultDecode
public:
/** DefaultDecode constructor. */
- DefaultDecode(O3CPU *_cpu, Params *params);
+ DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of decode. */
std::string name() const;
@@ -287,27 +288,27 @@ class DefaultDecode
/** Stat for total number of idle cycles. */
- Stats::Scalar<> decodeIdleCycles;
+ Stats::Scalar decodeIdleCycles;
/** Stat for total number of blocked cycles. */
- Stats::Scalar<> decodeBlockedCycles;
+ Stats::Scalar decodeBlockedCycles;
/** Stat for total number of normal running cycles. */
- Stats::Scalar<> decodeRunCycles;
+ Stats::Scalar decodeRunCycles;
/** Stat for total number of unblocking cycles. */
- Stats::Scalar<> decodeUnblockCycles;
+ Stats::Scalar decodeUnblockCycles;
/** Stat for total number of squashing cycles. */
- Stats::Scalar<> decodeSquashCycles;
+ Stats::Scalar decodeSquashCycles;
/** Stat for number of times a branch is resolved at decode. */
- Stats::Scalar<> decodeBranchResolved;
+ Stats::Scalar decodeBranchResolved;
/** Stat for number of times a branch mispredict is detected. */
- Stats::Scalar<> decodeBranchMispred;
+ Stats::Scalar decodeBranchMispred;
/** Stat for number of times decode detected a non-control instruction
* incorrectly predicted as a branch.
*/
- Stats::Scalar<> decodeControlMispred;
+ Stats::Scalar decodeControlMispred;
/** Stat for total number of decoded instructions. */
- Stats::Scalar<> decodeDecodedInsts;
+ Stats::Scalar decodeDecodedInsts;
/** Stat for total number of squashed instructions. */
- Stats::Scalar<> decodeSquashedInsts;
+ Stats::Scalar decodeSquashedInsts;
};
#endif // __CPU_O3_DECODE_HH__
diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh
index ce6738456..015bc8d7f 100644
--- a/src/cpu/o3/decode_impl.hh
+++ b/src/cpu/o3/decode_impl.hh
@@ -30,15 +30,17 @@
#include "cpu/o3/decode.hh"
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
-DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, Params *params)
+DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
renameToDecodeDelay(params->renameToDecodeDelay),
iewToDecodeDelay(params->iewToDecodeDelay),
commitToDecodeDelay(params->commitToDecodeDelay),
fetchToDecodeDelay(params->fetchToDecodeDelay),
decodeWidth(params->decodeWidth),
- numThreads(params->numberOfThreads)
+ numThreads(params->numThreads)
{
_status = Inactive;
diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/dyn_inst.cc
index 984b58f4b..d828ef1b0 100644
--- a/src/cpu/o3/sparc/dyn_inst.cc
+++ b/src/cpu/o3/dyn_inst.cc
@@ -28,9 +28,9 @@
* Authors: Gabe Black
*/
-#include "cpu/o3/sparc/dyn_inst_impl.hh"
-#include "cpu/o3/sparc/impl.hh"
+#include "cpu/o3/dyn_inst_impl.hh"
+#include "cpu/o3/impl.hh"
-// Force instantiation of SparcDynInst for all the implementations that
+// Force instantiation of BaseO3DynInst for all the implementations that
// are needed.
-template class SparcDynInst<SparcSimpleImpl>;
+template class BaseO3DynInst<O3CPUImpl>;
diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh
index a1f9e0591..292547b6b 100644
--- a/src/cpu/o3/dyn_inst.hh
+++ b/src/cpu/o3/dyn_inst.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * 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
@@ -25,36 +25,266 @@
* (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
+ * Authors: Kevin Lim
*/
#ifndef __CPU_O3_DYN_INST_HH__
#define __CPU_O3_DYN_INST_HH__
-#include "arch/isa_specific.hh"
-
-#if THE_ISA == ALPHA_ISA
- template <class Impl> class AlphaDynInst;
- struct AlphaSimpleImpl;
- typedef AlphaDynInst<AlphaSimpleImpl> O3DynInst;
-#elif THE_ISA == MIPS_ISA
- template <class Impl> class MipsDynInst;
- struct MipsSimpleImpl;
- typedef MipsDynInst<MipsSimpleImpl> O3DynInst;
-#elif THE_ISA == SPARC_ISA
- template <class Impl> class SparcDynInst;
- struct SparcSimpleImpl;
- typedef SparcDynInst<SparcSimpleImpl> O3DynInst;
-#elif THE_ISA == X86_ISA
- template <class Impl> class X86DynInst;
- struct X86SimpleImpl;
- typedef X86DynInst<X86SimpleImpl> O3DynInst;
-#elif THE_ISA == ARM_ISA
- template <class Impl> class ArmDynInst;
- struct ArmSimpleImpl;
- typedef ArmDynInst<ArmSimpleImpl> O3DynInst;
+#include "arch/isa_traits.hh"
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/cpu.hh"
+#include "cpu/o3/isa_specific.hh"
+
+class Packet;
+
+/**
+ * Mostly implementation & ISA specific AlphaDynInst. As with most
+ * other classes in the new CPU model, it is templated on the Impl to
+ * allow for passing in of all types, such as the CPU type and the ISA
+ * type. The AlphaDynInst serves as the primary interface to the CPU
+ * for instructions that are executing.
+ */
+template <class Impl>
+class BaseO3DynInst : public BaseDynInst<Impl>
+{
+ public:
+ /** Typedef for the CPU. */
+ typedef typename Impl::O3CPU O3CPU;
+
+ /** 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 index type. */
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ /** Misc register index type. */
+ typedef TheISA::MiscReg MiscReg;
+
+ enum {
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
+ };
+
+ public:
+ /** BaseDynInst constructor given a binary instruction. */
+ BaseO3DynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu);
+
+ /** BaseDynInst constructor given a binary instruction. */
+ BaseO3DynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu);
+
+ /** BaseDynInst constructor given a static inst pointer. */
+ BaseO3DynInst(StaticInstPtr &_staticInst);
+
+ /** Executes the instruction.*/
+ Fault execute();
+
+ /** Initiates the access. Only valid for memory operations. */
+ Fault initiateAcc();
+
+ /** Completes the access. Only valid for memory operations. */
+ Fault completeAcc(PacketPtr pkt);
+
+ private:
+ /** Initializes variables. */
+ void initVars();
+
+ public:
+ /** Reads a miscellaneous register. */
+ MiscReg readMiscRegNoEffect(int misc_reg)
+ {
+ return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
+ }
+
+ /** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return this->cpu->readMiscReg(misc_reg, this->threadNumber);
+ }
+
+ /** Sets a misc. register. */
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+ {
+ this->instResult.integer = val;
+ return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
+ }
+
+ /** 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)
+ {
+ return this->cpu->setMiscReg(misc_reg, val,
+ this->threadNumber);
+ }
+
+ /** Reads a miscellaneous register. */
+ TheISA::MiscReg 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.
+ */
+ TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
+ {
+ return this->cpu->readMiscReg(
+ si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ this->threadNumber);
+ }
+
+ /** Sets a misc. register. */
+ void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
+ {
+ this->instResult.integer = val;
+ return 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 setMiscRegOperand(const StaticInst *si, int idx,
+ const MiscReg &val)
+ {
+ return this->cpu->setMiscReg(
+ si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ val, this->threadNumber);
+ }
+
+#if FULL_SYSTEM
+ /** Calls hardware return from error interrupt. */
+ Fault hwrei();
+ /** Traps to handle specified fault. */
+ void trap(Fault fault);
+ bool simPalCheck(int palFunc);
#else
- #error "O3DynInst not defined for this ISA"
+ /** Calls a syscall. */
+ void syscall(int64_t callnum);
#endif
-#endif // __CPU_O3_DYN_INST_HH__
+ public:
+
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ uint64_t readIntRegOperand(const StaticInst *si, int idx)
+ {
+ return this->cpu->readIntReg(this->_srcRegIdx[idx]);
+ }
+
+ FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
+ {
+ return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
+ }
+
+ FloatReg readFloatRegOperand(const StaticInst *si, int idx)
+ {
+ return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
+ }
+
+ FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
+ int width)
+ {
+ return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
+ }
+
+ FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
+ {
+ return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
+ }
+
+ /** @todo: Make results into arrays so they can handle multiple dest
+ * registers.
+ */
+ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ {
+ this->cpu->setIntReg(this->_destRegIdx[idx], val);
+ BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
+ }
+
+ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
+ int width)
+ {
+ this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
+ BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
+ }
+
+ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
+ {
+ this->cpu->setFloatReg(this->_destRegIdx[idx], val);
+ BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
+ }
+
+ void setFloatRegOperandBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width)
+ {
+ this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
+ BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
+ }
+
+ void setFloatRegOperandBits(const StaticInst *si, int idx,
+ FloatRegBits val)
+ {
+ this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
+ BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
+ }
+
+#if THE_ISA == MIPS_ISA
+ uint64_t readRegOtherThread(int misc_reg)
+ {
+ panic("MIPS MT not defined for O3 CPU.\n");
+ return 0;
+ }
+
+ void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
+ {
+ panic("MIPS MT not defined for O3 CPU.\n");
+ }
+#endif
+
+ public:
+ /** Calculates EA part of a memory instruction. Currently unused,
+ * though it may be useful in the future if we want to split
+ * memory operations into EA calculation and memory access parts.
+ */
+ Fault calcEA()
+ {
+ return this->staticInst->eaCompInst()->execute(this, this->traceData);
+ }
+
+ /** Does the memory access part of a memory instruction. Currently unused,
+ * though it may be useful in the future if we want to split
+ * memory operations into EA calculation and memory access parts.
+ */
+ Fault memAccess()
+ {
+ return this->staticInst->memAccInst()->execute(this, this->traceData);
+ }
+};
+
+#endif // __CPU_O3_ALPHA_DYN_INST_HH__
+
diff --git a/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh
index 6dfe0ccdd..8d391ceaf 100644
--- a/src/cpu/o3/alpha/dyn_inst_impl.hh
+++ b/src/cpu/o3/dyn_inst_impl.hh
@@ -28,34 +28,35 @@
* Authors: Kevin Lim
*/
-#include "cpu/o3/alpha/dyn_inst.hh"
+#include "base/cp_annotate.hh"
+#include "cpu/o3/dyn_inst.hh"
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC,
- Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
+BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr staticInst,
+ Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC,
+ Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu)
: BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
+ Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
{
initVars();
}
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC,
- Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
+BaseO3DynInst<Impl>::BaseO3DynInst(ExtMachInst inst,
+ Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC,
+ Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu)
: BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
+ Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
{
initVars();
}
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
+BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr &_staticInst)
: BaseDynInst<Impl>(_staticInst)
{
initVars();
@@ -63,7 +64,7 @@ AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
template <class Impl>
void
-AlphaDynInst<Impl>::initVars()
+BaseO3DynInst<Impl>::initVars()
{
// Make sure to have the renamed register entries set to the same
// as the normal register entries. It will allow the IQ to work
@@ -80,7 +81,7 @@ AlphaDynInst<Impl>::initVars()
template <class Impl>
Fault
-AlphaDynInst<Impl>::execute()
+BaseO3DynInst<Impl>::execute()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
@@ -98,7 +99,7 @@ AlphaDynInst<Impl>::execute()
template <class Impl>
Fault
-AlphaDynInst<Impl>::initiateAcc()
+BaseO3DynInst<Impl>::initiateAcc()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
@@ -116,7 +117,7 @@ AlphaDynInst<Impl>::initiateAcc()
template <class Impl>
Fault
-AlphaDynInst<Impl>::completeAcc(PacketPtr pkt)
+BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt)
{
this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
@@ -126,8 +127,9 @@ AlphaDynInst<Impl>::completeAcc(PacketPtr pkt)
#if FULL_SYSTEM
template <class Impl>
Fault
-AlphaDynInst<Impl>::hwrei()
+BaseO3DynInst<Impl>::hwrei()
{
+#if THE_ISA == ALPHA_ISA
// Can only do a hwrei when in pal mode.
if (!(this->readPC() & 0x3))
return new AlphaISA::UnimplementedOpcodeFault;
@@ -135,33 +137,50 @@ AlphaDynInst<Impl>::hwrei()
// Set the next PC based on the value of the EXC_ADDR IPR.
this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
this->threadNumber));
+ if (CPA::available()) {
+ ThreadContext *tc = this->cpu->tcBase(this->threadNumber);
+ CPA::cpa()->swAutoBegin(tc, this->readNextPC());
+ }
// Tell CPU to clear any state it needs to if a hwrei is taken.
this->cpu->hwrei(this->threadNumber);
+#else
+#endif
// FIXME: XXX check for interrupts? XXX
return NoFault;
}
template <class Impl>
void
-AlphaDynInst<Impl>::trap(Fault fault)
+BaseO3DynInst<Impl>::trap(Fault fault)
{
this->cpu->trap(fault, this->threadNumber);
}
template <class Impl>
bool
-AlphaDynInst<Impl>::simPalCheck(int palFunc)
+BaseO3DynInst<Impl>::simPalCheck(int palFunc)
{
+#if THE_ISA != ALPHA_ISA
+ panic("simPalCheck called, but PAL only exists in Alpha!\n");
+#endif
return this->cpu->simPalCheck(palFunc, this->threadNumber);
}
#else
template <class Impl>
void
-AlphaDynInst<Impl>::syscall(int64_t callnum)
+BaseO3DynInst<Impl>::syscall(int64_t callnum)
{
+ // HACK: check CPU's nextPC before and after syscall. If it
+ // changes, update this instruction's nextPC because the syscall
+ // must have changed the nextPC.
+ Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber);
this->cpu->syscall(callnum, this->threadNumber);
+ Addr new_next_pc = this->cpu->readNextPC(this->threadNumber);
+ if (cpu_next_pc != new_next_pc) {
+ this->setNextPC(new_next_pc);
+ }
}
#endif
diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh
index d954bd1e7..08ccb094b 100644
--- a/src/cpu/o3/fetch.hh
+++ b/src/cpu/o3/fetch.hh
@@ -41,6 +41,8 @@
#include "mem/port.hh"
#include "sim/eventq.hh"
+class DerivO3CPUParams;
+
/**
* DefaultFetch class handles both single threaded and SMT fetch. Its
* width is specified by the parameters; each cycle it tries to fetch
@@ -58,7 +60,6 @@ class DefaultFetch
typedef typename Impl::DynInst DynInst;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
/** Typedefs from the CPU policy. */
typedef typename CPUPol::BPredUnit BPredUnit;
@@ -81,7 +82,7 @@ class DefaultFetch
public:
/** Default constructor. */
IcachePort(DefaultFetch<Impl> *_fetch)
- : Port(_fetch->name() + "-iport"), fetch(_fetch)
+ : Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch)
{ }
bool snoopRangeSent;
@@ -160,7 +161,7 @@ class DefaultFetch
public:
/** DefaultFetch constructor. */
- DefaultFetch(O3CPU *_cpu, Params *params);
+ DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of fetch. */
std::string name() const;
@@ -447,33 +448,33 @@ class DefaultFetch
// @todo: Consider making these vectors and tracking on a per thread basis.
/** Stat for total number of cycles stalled due to an icache miss. */
- Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar icacheStallCycles;
/** Stat for total number of fetched instructions. */
- Stats::Scalar<> fetchedInsts;
+ Stats::Scalar fetchedInsts;
/** Total number of fetched branches. */
- Stats::Scalar<> fetchedBranches;
+ Stats::Scalar fetchedBranches;
/** Stat for total number of predicted branches. */
- Stats::Scalar<> predictedBranches;
+ Stats::Scalar predictedBranches;
/** Stat for total number of cycles spent fetching. */
- Stats::Scalar<> fetchCycles;
+ Stats::Scalar fetchCycles;
/** Stat for total number of cycles spent squashing. */
- Stats::Scalar<> fetchSquashCycles;
+ Stats::Scalar fetchSquashCycles;
/** Stat for total number of cycles spent blocked due to other stages in
* the pipeline.
*/
- Stats::Scalar<> fetchIdleCycles;
+ Stats::Scalar fetchIdleCycles;
/** Total number of cycles spent blocked. */
- Stats::Scalar<> fetchBlockedCycles;
+ Stats::Scalar fetchBlockedCycles;
/** Total number of cycles spent in any other state. */
- Stats::Scalar<> fetchMiscStallCycles;
+ Stats::Scalar fetchMiscStallCycles;
/** Stat for total number of fetched cache lines. */
- Stats::Scalar<> fetchedCacheLines;
+ Stats::Scalar fetchedCacheLines;
/** Total number of outstanding icache accesses that were dropped
* due to a squash.
*/
- Stats::Scalar<> fetchIcacheSquashes;
+ Stats::Scalar fetchIcacheSquashes;
/** Distribution of number of instructions fetched each cycle. */
- Stats::Distribution<> fetchNisnDist;
+ Stats::Distribution fetchNisnDist;
/** Rate of how often fetch was idle. */
Stats::Formula idleRate;
/** Number of branch fetches per cycle. */
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
index 7d344fa33..79a4f2b7a 100644
--- a/src/cpu/o3/fetch_impl.hh
+++ b/src/cpu/o3/fetch_impl.hh
@@ -51,6 +51,8 @@
#include "sim/system.hh"
#endif // FULL_SYSTEM
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
void
DefaultFetch<Impl>::IcachePort::setPeer(Port *port)
@@ -111,7 +113,7 @@ DefaultFetch<Impl>::IcachePort::recvRetry()
}
template<class Impl>
-DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
+DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
branchPred(params),
predecoder(NULL),
@@ -123,14 +125,16 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
cacheBlocked(false),
retryPkt(NULL),
retryTid(-1),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
numFetchingThreads(params->smtNumFetchingThreads),
interruptPending(false),
drainPending(false),
switchedOut(false)
{
if (numThreads > Impl::MaxThreads)
- fatal("numThreads is not a valid value\n");
+ fatal("numThreads (%d) is larger than compiled limit (%d),\n"
+ "\tincrease MaxThreads in src/cpu/o3/impl.hh\n",
+ numThreads, static_cast<int>(Impl::MaxThreads));
// Set fetch stage's status to inactive.
_status = Inactive;
@@ -360,7 +364,7 @@ template<class Impl>
void
DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
{
- unsigned tid = pkt->req->getThreadNum();
+ unsigned tid = pkt->req->threadId();
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
@@ -591,12 +595,13 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
// Set the appropriate read size and flags as well.
// Build request here.
RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0,
- fetch_PC, cpu->readCpuId(), tid);
+ fetch_PC, cpu->thread[tid]->contextId(),
+ tid);
memReq[tid] = mem_req;
// Translate the instruction request.
- fault = cpu->translateInstReq(mem_req, cpu->thread[tid]);
+ fault = cpu->itb->translateAtomic(mem_req, cpu->thread[tid]->getTC());
// In the case of faults, the fetch stage may need to stall and wait
// for the ITB miss to be handled.
diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh
index 457e2a024..3458f09d6 100644
--- a/src/cpu/o3/iew.hh
+++ b/src/cpu/o3/iew.hh
@@ -41,6 +41,7 @@
#include "cpu/o3/scoreboard.hh"
#include "cpu/o3/lsq.hh"
+class DerivO3CPUParams;
class FUPool;
/**
@@ -70,7 +71,6 @@ class DefaultIEW
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
typedef typename CPUPol::IQ IQ;
typedef typename CPUPol::RenameMap RenameMap;
@@ -115,7 +115,7 @@ class DefaultIEW
public:
/** Constructs a DefaultIEW with the given parameters. */
- DefaultIEW(O3CPU *_cpu, Params *params);
+ DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of the DefaultIEW stage. */
std::string name() const;
@@ -208,6 +208,9 @@ class DefaultIEW
/** Returns if the LSQ has any stores to writeback. */
bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); }
+ /** Returns if the LSQ has any stores to writeback. */
+ bool hasStoresToWB(unsigned tid) { return ldstQueue.hasStoresToWB(tid); }
+
void incrWb(InstSeqNum &sn)
{
if (++wbOutstanding == wbMax)
@@ -462,69 +465,69 @@ class DefaultIEW
bool switchedOut;
/** Stat for total number of idle cycles. */
- Stats::Scalar<> iewIdleCycles;
+ Stats::Scalar iewIdleCycles;
/** Stat for total number of squashing cycles. */
- Stats::Scalar<> iewSquashCycles;
+ Stats::Scalar iewSquashCycles;
/** Stat for total number of blocking cycles. */
- Stats::Scalar<> iewBlockCycles;
+ Stats::Scalar iewBlockCycles;
/** Stat for total number of unblocking cycles. */
- Stats::Scalar<> iewUnblockCycles;
+ Stats::Scalar iewUnblockCycles;
/** Stat for total number of instructions dispatched. */
- Stats::Scalar<> iewDispatchedInsts;
+ Stats::Scalar iewDispatchedInsts;
/** Stat for total number of squashed instructions dispatch skips. */
- Stats::Scalar<> iewDispSquashedInsts;
+ Stats::Scalar iewDispSquashedInsts;
/** Stat for total number of dispatched load instructions. */
- Stats::Scalar<> iewDispLoadInsts;
+ Stats::Scalar iewDispLoadInsts;
/** Stat for total number of dispatched store instructions. */
- Stats::Scalar<> iewDispStoreInsts;
+ Stats::Scalar iewDispStoreInsts;
/** Stat for total number of dispatched non speculative instructions. */
- Stats::Scalar<> iewDispNonSpecInsts;
+ Stats::Scalar iewDispNonSpecInsts;
/** Stat for number of times the IQ becomes full. */
- Stats::Scalar<> iewIQFullEvents;
+ Stats::Scalar iewIQFullEvents;
/** Stat for number of times the LSQ becomes full. */
- Stats::Scalar<> iewLSQFullEvents;
+ Stats::Scalar iewLSQFullEvents;
/** Stat for total number of memory ordering violation events. */
- Stats::Scalar<> memOrderViolationEvents;
+ Stats::Scalar memOrderViolationEvents;
/** Stat for total number of incorrect predicted taken branches. */
- Stats::Scalar<> predictedTakenIncorrect;
+ Stats::Scalar predictedTakenIncorrect;
/** Stat for total number of incorrect predicted not taken branches. */
- Stats::Scalar<> predictedNotTakenIncorrect;
+ Stats::Scalar predictedNotTakenIncorrect;
/** Stat for total number of mispredicted branches detected at execute. */
Stats::Formula branchMispredicts;
/** Stat for total number of executed instructions. */
- Stats::Scalar<> iewExecutedInsts;
+ Stats::Scalar iewExecutedInsts;
/** Stat for total number of executed load instructions. */
- Stats::Vector<> iewExecLoadInsts;
+ Stats::Vector iewExecLoadInsts;
/** Stat for total number of executed store instructions. */
-// Stats::Scalar<> iewExecStoreInsts;
+// Stats::Scalar iewExecStoreInsts;
/** Stat for total number of squashed instructions skipped at execute. */
- Stats::Scalar<> iewExecSquashedInsts;
+ Stats::Scalar iewExecSquashedInsts;
/** Number of executed software prefetches. */
- Stats::Vector<> iewExecutedSwp;
+ Stats::Vector iewExecutedSwp;
/** Number of executed nops. */
- Stats::Vector<> iewExecutedNop;
+ Stats::Vector iewExecutedNop;
/** Number of executed meomory references. */
- Stats::Vector<> iewExecutedRefs;
+ Stats::Vector iewExecutedRefs;
/** Number of executed branches. */
- Stats::Vector<> iewExecutedBranches;
+ Stats::Vector iewExecutedBranches;
/** Number of executed store instructions. */
Stats::Formula iewExecStoreInsts;
/** Number of instructions executed per cycle. */
Stats::Formula iewExecRate;
/** Number of instructions sent to commit. */
- Stats::Vector<> iewInstsToCommit;
+ Stats::Vector iewInstsToCommit;
/** Number of instructions that writeback. */
- Stats::Vector<> writebackCount;
+ Stats::Vector writebackCount;
/** Number of instructions that wake consumers. */
- Stats::Vector<> producerInst;
+ Stats::Vector producerInst;
/** Number of instructions that wake up from producers. */
- Stats::Vector<> consumerInst;
+ Stats::Vector consumerInst;
/** Number of instructions that were delayed in writing back due
* to resource contention.
*/
- Stats::Vector<> wbPenalized;
+ Stats::Vector wbPenalized;
/** Number of instructions per cycle written back. */
Stats::Formula wbRate;
/** Average number of woken instructions per writeback. */
diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh
index 84d10e966..1daecd669 100644
--- a/src/cpu/o3/iew_impl.hh
+++ b/src/cpu/o3/iew_impl.hh
@@ -37,9 +37,10 @@
#include "base/timebuf.hh"
#include "cpu/o3/fu_pool.hh"
#include "cpu/o3/iew.hh"
+#include "params/DerivO3CPU.hh"
template<class Impl>
-DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params)
+DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params)
: issueToExecQueue(params->backComSize, params->forwardComSize),
cpu(_cpu),
instQueue(_cpu, this, params),
@@ -52,7 +53,7 @@ DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params)
issueWidth(params->issueWidth),
wbOutstanding(0),
wbWidth(params->wbWidth),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
switchedOut(false)
{
_status = Active;
diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/impl.hh
index 0a970c2f0..4b29b4daa 100644
--- a/src/cpu/o3/sparc/impl.hh
+++ b/src/cpu/o3/impl.hh
@@ -25,24 +25,23 @@
* (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: Gabe Black
+ * Authors: Kevin Lim
*/
-#ifndef __CPU_O3_SPARC_IMPL_HH__
-#define __CPU_O3_SPARC_IMPL_HH__
+#ifndef __CPU_O3_IMPL_HH__
+#define __CPU_O3_IMPL_HH__
-#include "arch/sparc/isa_traits.hh"
+#include "arch/isa_traits.hh"
-#include "cpu/o3/sparc/params.hh"
#include "cpu/o3/cpu_policy.hh"
// Forward declarations.
template <class Impl>
-class SparcDynInst;
+class BaseO3DynInst;
template <class Impl>
-class SparcO3CPU;
+class FullO3CPU;
/** Implementation specific struct that defines several key types to the
* CPU, the stages within the CPU, the time buffers, and the DynInst.
@@ -52,16 +51,16 @@ class SparcO3CPU;
* This is one of the key things that must be defined for each hardware
* specific CPU implementation.
*/
-struct SparcSimpleImpl
+struct O3CPUImpl
{
/** The type of MachInst. */
typedef TheISA::MachInst MachInst;
/** The CPU policy to be used, which defines all of the CPU stages. */
- typedef SimpleCPUPolicy<SparcSimpleImpl> CPUPol;
+ typedef SimpleCPUPolicy<O3CPUImpl> CPUPol;
/** The DynInst type to be used. */
- typedef SparcDynInst<SparcSimpleImpl> DynInst;
+ typedef BaseO3DynInst<O3CPUImpl> DynInst;
/** The refcounted DynInst pointer to be used. In most cases this is
* what should be used, and not DynInst *.
@@ -69,7 +68,7 @@ struct SparcSimpleImpl
typedef RefCountingPtr<DynInst> DynInstPtr;
/** The O3CPU type to be used. */
- typedef SparcO3CPU<SparcSimpleImpl> O3CPU;
+ typedef FullO3CPU<O3CPUImpl> O3CPU;
/** Same typedef, but for CPUType. BaseDynInst may not always use
* an O3 CPU, so it's clearer to call it CPUType instead in that
@@ -77,16 +76,10 @@ struct SparcSimpleImpl
*/
typedef O3CPU CPUType;
- /** The Params to be passed to each stage. */
- typedef SparcSimpleParams Params;
-
enum {
MaxWidth = 8,
MaxThreads = 4
};
};
-/** The O3Impl to be used. */
-typedef SparcSimpleImpl O3CPUImpl;
-
#endif // __CPU_O3_SPARC_IMPL_HH__
diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh
index d0f503977..0c3f44436 100644
--- a/src/cpu/o3/inst_queue.hh
+++ b/src/cpu/o3/inst_queue.hh
@@ -41,8 +41,10 @@
#include "cpu/inst_seq.hh"
#include "cpu/o3/dep_graph.hh"
#include "cpu/op_class.hh"
+#include "sim/eventq.hh"
#include "sim/host.hh"
+class DerivO3CPUParams;
class FUPool;
class MemInterface;
@@ -70,7 +72,6 @@ class InstructionQueue
//Typedefs from the Impl.
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::Params Params;
typedef typename Impl::CPUPol::IEW IEW;
typedef typename Impl::CPUPol::MemDepUnit MemDepUnit;
@@ -110,7 +111,7 @@ class InstructionQueue
};
/** Constructs an IQ. */
- InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params);
+ InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params);
/** Destructs the IQ. */
~InstructionQueue();
@@ -442,58 +443,58 @@ class InstructionQueue
void dumpInsts();
/** Stat for number of instructions added. */
- Stats::Scalar<> iqInstsAdded;
+ Stats::Scalar iqInstsAdded;
/** Stat for number of non-speculative instructions added. */
- Stats::Scalar<> iqNonSpecInstsAdded;
+ Stats::Scalar iqNonSpecInstsAdded;
- Stats::Scalar<> iqInstsIssued;
+ Stats::Scalar iqInstsIssued;
/** Stat for number of integer instructions issued. */
- Stats::Scalar<> iqIntInstsIssued;
+ Stats::Scalar iqIntInstsIssued;
/** Stat for number of floating point instructions issued. */
- Stats::Scalar<> iqFloatInstsIssued;
+ Stats::Scalar iqFloatInstsIssued;
/** Stat for number of branch instructions issued. */
- Stats::Scalar<> iqBranchInstsIssued;
+ Stats::Scalar iqBranchInstsIssued;
/** Stat for number of memory instructions issued. */
- Stats::Scalar<> iqMemInstsIssued;
+ Stats::Scalar iqMemInstsIssued;
/** Stat for number of miscellaneous instructions issued. */
- Stats::Scalar<> iqMiscInstsIssued;
+ Stats::Scalar iqMiscInstsIssued;
/** Stat for number of squashed instructions that were ready to issue. */
- Stats::Scalar<> iqSquashedInstsIssued;
+ Stats::Scalar iqSquashedInstsIssued;
/** Stat for number of squashed instructions examined when squashing. */
- Stats::Scalar<> iqSquashedInstsExamined;
+ Stats::Scalar iqSquashedInstsExamined;
/** Stat for number of squashed instruction operands examined when
* squashing.
*/
- Stats::Scalar<> iqSquashedOperandsExamined;
+ Stats::Scalar iqSquashedOperandsExamined;
/** Stat for number of non-speculative instructions removed due to a squash.
*/
- Stats::Scalar<> iqSquashedNonSpecRemoved;
+ Stats::Scalar iqSquashedNonSpecRemoved;
// Also include number of instructions rescheduled and replayed.
/** Distribution of number of instructions in the queue.
* @todo: Need to create struct to track the entry time for each
* instruction. */
-// Stats::VectorDistribution<> queueResDist;
+// Stats::VectorDistribution queueResDist;
/** Distribution of the number of instructions issued. */
- Stats::Distribution<> numIssuedDist;
+ Stats::Distribution numIssuedDist;
/** Distribution of the cycles it takes to issue an instruction.
* @todo: Need to create struct to track the ready time for each
* instruction. */
-// Stats::VectorDistribution<> issueDelayDist;
+// Stats::VectorDistribution issueDelayDist;
/** Number of times an instruction could not be issued because a
* FU was busy.
*/
- Stats::Vector<> statFuBusy;
-// Stats::Vector<> dist_unissued;
+ Stats::Vector statFuBusy;
+// Stats::Vector dist_unissued;
/** Stat for total number issued for each instruction type. */
- Stats::Vector2d<> statIssuedInstType;
+ Stats::Vector2d statIssuedInstType;
/** Number of instructions issued per cycle. */
Stats::Formula issueRate;
/** Number of times the FU was busy. */
- Stats::Vector<> fuBusy;
+ Stats::Vector fuBusy;
/** Number of times the FU was busy per instruction issued. */
Stats::Formula fuBusyRate;
};
diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh
index fb06f20df..1d0f4b9f6 100644
--- a/src/cpu/o3/inst_queue_impl.hh
+++ b/src/cpu/o3/inst_queue_impl.hh
@@ -37,12 +37,13 @@
#include "enums/OpClass.hh"
#include "sim/core.hh"
+#include "params/DerivO3CPU.hh"
+
template <class Impl>
InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst,
- int fu_idx,
- InstructionQueue<Impl> *iq_ptr)
- : Event(&mainEventQueue, Stat_Event_Pri),
- inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false)
+ int fu_idx, InstructionQueue<Impl> *iq_ptr)
+ : Event(Stat_Event_Pri), inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr),
+ freeFU(false)
{
this->setFlags(Event::AutoDelete);
}
@@ -65,7 +66,7 @@ InstructionQueue<Impl>::FUCompletion::description() const
template <class Impl>
InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr,
- Params *params)
+ DerivO3CPUParams *params)
: cpu(cpu_ptr),
iewStage(iew_ptr),
fuPool(params->fuPool),
@@ -79,7 +80,7 @@ InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr,
switchedOut = false;
- numThreads = params->numberOfThreads;
+ numThreads = params->numThreads;
// Set the number of physical registers as the number of int + float
numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
@@ -752,7 +753,7 @@ InstructionQueue<Impl>::scheduleReadyInsts()
FUCompletion *execution = new FUCompletion(issuing_inst,
idx, this);
- execution->schedule(curTick + cpu->ticks(op_latency - 1));
+ cpu->schedule(execution, curTick + cpu->ticks(op_latency - 1));
// @todo: Enforce that issue_latency == 1 or op_latency
if (issue_latency > 1) {
diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh
index 72a8d4021..e9347af91 100755
--- a/src/cpu/o3/isa_specific.hh
+++ b/src/cpu/o3/isa_specific.hh
@@ -30,21 +30,5 @@
#include "cpu/base.hh"
-#if THE_ISA == ALPHA_ISA
- #include "cpu/o3/alpha/cpu.hh"
- #include "cpu/o3/alpha/impl.hh"
- #include "cpu/o3/alpha/params.hh"
- #include "cpu/o3/alpha/dyn_inst.hh"
-#elif THE_ISA == MIPS_ISA
- #include "cpu/o3/mips/cpu.hh"
- #include "cpu/o3/mips/impl.hh"
- #include "cpu/o3/mips/params.hh"
- #include "cpu/o3/mips/dyn_inst.hh"
-#elif THE_ISA == SPARC_ISA
- #include "cpu/o3/sparc/cpu.hh"
- #include "cpu/o3/sparc/impl.hh"
- #include "cpu/o3/sparc/params.hh"
- #include "cpu/o3/sparc/dyn_inst.hh"
-#else
- #error "ISA-specific header files O3CPU not defined ISA"
-#endif
+#include "cpu/o3/impl.hh"
+#include "cpu/o3/dyn_inst.hh"
diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh
index 06de608e0..cf27552d4 100644
--- a/src/cpu/o3/lsq.hh
+++ b/src/cpu/o3/lsq.hh
@@ -40,10 +40,11 @@
#include "mem/port.hh"
#include "sim/sim_object.hh"
+class DerivO3CPUParams;
+
template <class Impl>
class LSQ {
public:
- typedef typename Impl::Params Params;
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::CPUPol::IEW IEW;
@@ -57,7 +58,7 @@ class LSQ {
};
/** Constructs an LSQ with the given parameters. */
- LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params);
+ LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params);
/** Returns the name of the LSQ. */
std::string name() const;
@@ -297,7 +298,7 @@ class LSQ {
public:
/** Default constructor. */
DcachePort(LSQ *_lsq)
- : Port(_lsq->name() + "-dport"), lsq(_lsq)
+ : Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq)
{ }
bool snoopRangeSent;
@@ -370,7 +371,7 @@ template <class T>
Fault
LSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
{
- unsigned tid = req->getThreadNum();
+ unsigned tid = req->threadId();
return thread[tid].read(req, data, load_idx);
}
@@ -380,7 +381,7 @@ template <class T>
Fault
LSQ<Impl>::write(RequestPtr req, T &data, int store_idx)
{
- unsigned tid = req->getThreadNum();
+ unsigned tid = req->threadId();
return thread[tid].write(req, data, store_idx);
}
diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh
index 8ed6f7f54..8f9f63081 100644
--- a/src/cpu/o3/lsq_impl.hh
+++ b/src/cpu/o3/lsq_impl.hh
@@ -34,6 +34,8 @@
#include "cpu/o3/lsq.hh"
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
void
LSQ<Impl>::DcachePort::setPeer(Port *port)
@@ -83,7 +85,7 @@ LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
if (pkt->isError())
DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr());
if (pkt->isResponse()) {
- lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt);
+ lsq->thread[pkt->req->threadId()].completeDataAccess(pkt);
}
else {
// must be a snoop
@@ -111,11 +113,11 @@ LSQ<Impl>::DcachePort::recvRetry()
}
template <class Impl>
-LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params)
+LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
: cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this),
LQEntries(params->LQEntries),
SQEntries(params->SQEntries),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
retryTid(-1)
{
dcachePort.snoopRangeSent = false;
@@ -582,17 +584,14 @@ LSQ<Impl>::hasStoresToWB()
std::list<unsigned>::iterator threads = activeThreads->begin();
std::list<unsigned>::iterator end = activeThreads->end();
- if (threads == end)
- return false;
-
while (threads != end) {
unsigned tid = *threads++;
- if (!hasStoresToWB(tid))
- return false;
+ if (hasStoresToWB(tid))
+ return true;
}
- return true;
+ return false;
}
template<class Impl>
@@ -605,11 +604,11 @@ LSQ<Impl>::willWB()
while (threads != end) {
unsigned tid = *threads++;
- if (!willWB(tid))
- return false;
+ if (willWB(tid))
+ return true;
}
- return true;
+ return false;
}
template<class Impl>
diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh
index 128a71dbc..5323e3a47 100644
--- a/src/cpu/o3/lsq_unit.hh
+++ b/src/cpu/o3/lsq_unit.hh
@@ -40,11 +40,14 @@
#include "arch/faults.hh"
#include "arch/locked_mem.hh"
#include "config/full_system.hh"
+#include "base/fast_alloc.hh"
#include "base/hashmap.hh"
#include "cpu/inst_seq.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
+class DerivO3CPUParams;
+
/**
* Class that implements the actual LQ and SQ for each specific
* thread. Both are circular queues; load entries are freed upon
@@ -62,7 +65,6 @@ class LSQUnit {
protected:
typedef TheISA::IntReg IntReg;
public:
- typedef typename Impl::Params Params;
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::CPUPol::IEW IEW;
@@ -74,8 +76,9 @@ class LSQUnit {
LSQUnit();
/** Initializes the LSQ unit with the specified number of entries. */
- void init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,
- unsigned maxLQEntries, unsigned maxSQEntries, unsigned id);
+ void init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
+ LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries,
+ unsigned id);
/** Returns the name of the LSQ unit. */
std::string name() const;
@@ -245,7 +248,7 @@ class LSQUnit {
Port *dcachePort;
/** Derived class to hold any sender state the LSQ needs. */
- class LSQSenderState : public Packet::SenderState
+ class LSQSenderState : public Packet::SenderState, public FastAlloc
{
public:
/** Default constructor. */
@@ -406,35 +409,35 @@ class LSQUnit {
// of that in stage that is one level up, and only call executeLoad/Store
// the appropriate number of times.
/** Total number of loads forwaded from LSQ stores. */
- Stats::Scalar<> lsqForwLoads;
+ Stats::Scalar lsqForwLoads;
/** Total number of loads ignored due to invalid addresses. */
- Stats::Scalar<> invAddrLoads;
+ Stats::Scalar invAddrLoads;
/** Total number of squashed loads. */
- Stats::Scalar<> lsqSquashedLoads;
+ Stats::Scalar lsqSquashedLoads;
/** Total number of responses from the memory system that are
* ignored due to the instruction already being squashed. */
- Stats::Scalar<> lsqIgnoredResponses;
+ Stats::Scalar lsqIgnoredResponses;
/** Tota number of memory ordering violations. */
- Stats::Scalar<> lsqMemOrderViolation;
+ Stats::Scalar lsqMemOrderViolation;
/** Total number of squashed stores. */
- Stats::Scalar<> lsqSquashedStores;
+ Stats::Scalar lsqSquashedStores;
/** Total number of software prefetches ignored due to invalid addresses. */
- Stats::Scalar<> invAddrSwpfs;
+ Stats::Scalar invAddrSwpfs;
/** Ready loads blocked due to partial store-forwarding. */
- Stats::Scalar<> lsqBlockedLoads;
+ Stats::Scalar lsqBlockedLoads;
/** Number of loads that were rescheduled. */
- Stats::Scalar<> lsqRescheduledLoads;
+ Stats::Scalar lsqRescheduledLoads;
/** Number of times the LSQ is blocked due to the cache. */
- Stats::Scalar<> lsqCacheBlocked;
+ Stats::Scalar lsqCacheBlocked;
public:
/** Executes the load at the given index. */
@@ -581,7 +584,7 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
// We'll say this has a 1 cycle load-store forwarding latency
// for now.
// @todo: Need to make this a parameter.
- wb->schedule(curTick);
+ cpu->schedule(wb, curTick);
++lsqForwLoads;
return NoFault;
diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh
index e6ff5e931..85662d496 100644
--- a/src/cpu/o3/lsq_unit_impl.hh
+++ b/src/cpu/o3/lsq_unit_impl.hh
@@ -45,7 +45,7 @@
template<class Impl>
LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,
LSQUnit *lsq_ptr)
- : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
+ : inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
{
this->setFlags(Event::AutoDelete);
}
@@ -112,8 +112,9 @@ LSQUnit<Impl>::LSQUnit()
template<class Impl>
void
-LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,
- unsigned maxLQEntries, unsigned maxSQEntries, unsigned id)
+LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
+ LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries,
+ unsigned id)
{
cpu = cpu_ptr;
iewStage = iew_ptr;
@@ -683,7 +684,7 @@ LSQUnit<Impl>::writebackStores()
"Instantly completing it.\n",
inst->seqNum);
WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
- wb->schedule(curTick + 1);
+ cpu->schedule(wb, curTick + 1);
completeStore(storeWBIdx);
incrStIdx(storeWBIdx);
continue;
diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh
index a12a3001b..4f9e7c9f7 100644
--- a/src/cpu/o3/mem_dep_unit.hh
+++ b/src/cpu/o3/mem_dep_unit.hh
@@ -48,6 +48,8 @@ struct SNHash {
}
};
+class DerivO3CPUParams;
+
template <class Impl>
class InstructionQueue;
@@ -63,25 +65,28 @@ class InstructionQueue;
* dependence prediction schemes.
*/
template <class MemDepPred, class Impl>
-class MemDepUnit {
+class MemDepUnit
+{
+ protected:
+ std::string _name;
+
public:
- typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
/** Empty constructor. Must call init() prior to using in this case. */
MemDepUnit();
/** Constructs a MemDepUnit with given parameters. */
- MemDepUnit(Params *params);
+ MemDepUnit(DerivO3CPUParams *params);
/** Frees up any memory allocated. */
~MemDepUnit();
/** Returns the name of the memory dependence unit. */
- std::string name() const;
+ std::string name() const { return _name; }
/** Initializes the unit with parameters and a thread id. */
- void init(Params *params, int tid);
+ void init(DerivO3CPUParams *params, int tid);
/** Registers statistics. */
void regStats();
@@ -252,13 +257,13 @@ class MemDepUnit {
int id;
/** Stat for number of inserted loads. */
- Stats::Scalar<> insertedLoads;
+ Stats::Scalar insertedLoads;
/** Stat for number of inserted stores. */
- Stats::Scalar<> insertedStores;
+ Stats::Scalar insertedStores;
/** Stat for number of conflicting loads that had to wait for a store. */
- Stats::Scalar<> conflictingLoads;
+ Stats::Scalar conflictingLoads;
/** Stat for number of conflicting stores that had to wait for a store. */
- Stats::Scalar<> conflictingStores;
+ Stats::Scalar conflictingStores;
};
#endif // __CPU_O3_MEM_DEP_UNIT_HH__
diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh
index 64558efaa..8754539f9 100644
--- a/src/cpu/o3/mem_dep_unit_impl.hh
+++ b/src/cpu/o3/mem_dep_unit_impl.hh
@@ -33,6 +33,8 @@
#include "cpu/o3/inst_queue.hh"
#include "cpu/o3/mem_dep_unit.hh"
+#include "params/DerivO3CPU.hh"
+
template <class MemDepPred, class Impl>
MemDepUnit<MemDepPred, Impl>::MemDepUnit()
: loadBarrier(false), loadBarrierSN(0), storeBarrier(false),
@@ -41,8 +43,9 @@ MemDepUnit<MemDepPred, Impl>::MemDepUnit()
}
template <class MemDepPred, class Impl>
-MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params)
- : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false),
+MemDepUnit<MemDepPred, Impl>::MemDepUnit(DerivO3CPUParams *params)
+ : _name(params->name + ".memdepunit"),
+ depPred(params->SSITSize, params->LFSTSize), loadBarrier(false),
loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL)
{
DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n");
@@ -74,18 +77,12 @@ MemDepUnit<MemDepPred, Impl>::~MemDepUnit()
}
template <class MemDepPred, class Impl>
-std::string
-MemDepUnit<MemDepPred, Impl>::name() const
-{
- return "memdepunit";
-}
-
-template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid)
+MemDepUnit<MemDepPred, Impl>::init(DerivO3CPUParams *params, int tid)
{
DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid);
+ _name = csprintf("%s.memDep%d", params->name, tid);
id = tid;
depPred.init(params->SSITSize, params->LFSTSize);
@@ -96,19 +93,19 @@ void
MemDepUnit<MemDepPred, Impl>::regStats()
{
insertedLoads
- .name(name() + ".memDep.insertedLoads")
+ .name(name() + ".insertedLoads")
.desc("Number of loads inserted to the mem dependence unit.");
insertedStores
- .name(name() + ".memDep.insertedStores")
+ .name(name() + ".insertedStores")
.desc("Number of stores inserted to the mem dependence unit.");
conflictingLoads
- .name(name() + ".memDep.conflictingLoads")
+ .name(name() + ".conflictingLoads")
.desc("Number of conflicting loads.");
conflictingStores
- .name(name() + ".memDep.conflictingStores")
+ .name(name() + ".conflictingStores")
.desc("Number of conflicting stores.");
}
diff --git a/src/cpu/o3/mips/cpu.cc b/src/cpu/o3/mips/cpu.cc
deleted file mode 100755
index 420f460b2..000000000
--- a/src/cpu/o3/mips/cpu.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#include "cpu/o3/mips/impl.hh"
-#include "cpu/o3/mips/cpu_impl.hh"
-#include "cpu/o3/mips/dyn_inst.hh"
-
-// Force instantiation of MipsO3CPU for all the implemntations that are
-// needed. Consider merging this and mips_dyn_inst.cc, and maybe all
-// classes that depend on a certain impl, into one file (mips_impl.cc?).
-template class MipsO3CPU<MipsSimpleImpl>;
diff --git a/src/cpu/o3/mips/cpu.hh b/src/cpu/o3/mips/cpu.hh
deleted file mode 100755
index 3724ced46..000000000
--- a/src/cpu/o3/mips/cpu.hh
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_CPU_HH__
-#define __CPU_O3_MIPS_CPU_HH__
-
-#include "arch/mips/regfile.hh"
-#include "arch/mips/syscallreturn.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/o3/cpu.hh"
-#include "sim/byteswap.hh"
-#include "sim/faults.hh"
-
-class EndQuiesceEvent;
-namespace Kernel {
- class Statistics;
-};
-
-class TranslatingPort;
-
-/**
- * MipsO3CPU class. Derives from the FullO3CPU class, and
- * implements all ISA and implementation specific functions of the
- * CPU. This is the CPU class that is used for the SimObjects, and is
- * what is given to the DynInsts. Most of its state exists in the
- * FullO3CPU; the state is has is mainly for ISA specific
- * functionality.
- */
-template <class Impl>
-class MipsO3CPU : public FullO3CPU<Impl>
-{
- public:
- typedef O3ThreadState<Impl> ImplState;
- typedef O3ThreadState<Impl> Thread;
- typedef typename Impl::Params Params;
-
- /** Constructs an MipsO3CPU with the given parameters. */
- MipsO3CPU(Params *params);
-
- /** Registers statistics. */
- void regStats();
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
-
- /** Reads a misc. register, including any side effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::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 TheISA::MiscReg &val, unsigned tid);
-
- /** Initiates a squash of all in-flight instructions for a given
- * thread. The source of the squash is an external update of
- * state through the TC.
- */
- void squashFromTC(unsigned tid);
-
- /** Traps to handle given fault. */
- void trap(Fault fault, unsigned tid);
-
- /** Executes a syscall.
- * @todo: Determine if this needs to be virtual.
- */
- void syscall(int64_t callnum, int tid);
- /** Gets a syscall argument. */
- TheISA::IntReg getSyscallArg(int i, int tid);
-
- /** Used to shift args for indirect syscall. */
- void setSyscallArg(int i, TheISA::IntReg val, int tid);
-
- /** Sets the return value of a syscall. */
- void setSyscallReturn(SyscallReturn return_value, int tid);
-
- /** CPU read function, forwards read to LSQ. */
- template <class T>
- Fault read(RequestPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- /** CPU write function, forwards write to LSQ. */
- template <class T>
- Fault write(RequestPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
- Addr lockAddr;
-
- /** Temporary fix for the lock flag, works in the UP case. */
- bool lockFlag;
-};
-
-#endif // __CPU_O3_MIPS_CPU_HH__
diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc
deleted file mode 100644
index 4690b9804..000000000
--- a/src/cpu/o3/mips/cpu_builder.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#include <string>
-
-#include "config/use_checker.hh"
-#include "cpu/base.hh"
-#include "cpu/o3/mips/cpu.hh"
-#include "cpu/o3/mips/impl.hh"
-#include "cpu/o3/mips/params.hh"
-#include "cpu/o3/fu_pool.hh"
-#include "params/DerivO3CPU.hh"
-
-class DerivO3CPU : public MipsO3CPU<MipsSimpleImpl>
-{
- public:
- DerivO3CPU(MipsSimpleParams *p)
- : MipsO3CPU<MipsSimpleImpl>(p)
- { }
-};
-
-DerivO3CPU *
-DerivO3CPUParams::create()
-{
- DerivO3CPU *cpu;
-
- // In non-full-system mode, we infer the number of threads from
- // the workload if it's not explicitly specified.
- int actual_num_threads =
- (numThreads >= workload.size()) ? numThreads : workload.size();
-
- if (workload.size() == 0) {
- fatal("Must specify at least one workload!");
- }
-
- MipsSimpleParams *params = new MipsSimpleParams;
-
- params->clock = clock;
- params->phase = phase;
-
- params->tracer = tracer;
-
- params->name = name;
- params->numberOfThreads = actual_num_threads;
- params->cpu_id = cpu_id;
- params->activity = activity;
-
- params->workload = workload;
-
-#if USE_CHECKER
- params->checker = checker;
-#endif
-
- params->max_insts_any_thread = max_insts_any_thread;
- params->max_insts_all_threads = max_insts_all_threads;
- params->max_loads_any_thread = max_loads_any_thread;
- params->max_loads_all_threads = max_loads_all_threads;
-
- //
- // Caches
- //
- params->cachePorts = cachePorts;
-
- params->decodeToFetchDelay = decodeToFetchDelay;
- params->renameToFetchDelay = renameToFetchDelay;
- params->iewToFetchDelay = iewToFetchDelay;
- params->commitToFetchDelay = commitToFetchDelay;
- params->fetchWidth = fetchWidth;
-
- params->renameToDecodeDelay = renameToDecodeDelay;
- params->iewToDecodeDelay = iewToDecodeDelay;
- params->commitToDecodeDelay = commitToDecodeDelay;
- params->fetchToDecodeDelay = fetchToDecodeDelay;
- params->decodeWidth = decodeWidth;
-
- params->iewToRenameDelay = iewToRenameDelay;
- params->commitToRenameDelay = commitToRenameDelay;
- params->decodeToRenameDelay = decodeToRenameDelay;
- params->renameWidth = renameWidth;
-
- params->commitToIEWDelay = commitToIEWDelay;
- params->renameToIEWDelay = renameToIEWDelay;
- params->issueToExecuteDelay = issueToExecuteDelay;
- params->dispatchWidth = dispatchWidth;
- params->issueWidth = issueWidth;
- params->wbWidth = wbWidth;
- params->wbDepth = wbDepth;
- params->fuPool = fuPool;
-
- params->iewToCommitDelay = iewToCommitDelay;
- params->renameToROBDelay = renameToROBDelay;
- params->commitWidth = commitWidth;
- params->squashWidth = squashWidth;
- params->trapLatency = trapLatency;
-
- params->backComSize = backComSize;
- params->forwardComSize = forwardComSize;
-
- params->predType = predType;
- params->localPredictorSize = localPredictorSize;
- params->localCtrBits = localCtrBits;
- params->localHistoryTableSize = localHistoryTableSize;
- params->localHistoryBits = localHistoryBits;
- params->globalPredictorSize = globalPredictorSize;
- params->globalCtrBits = globalCtrBits;
- params->globalHistoryBits = globalHistoryBits;
- params->choicePredictorSize = choicePredictorSize;
- params->choiceCtrBits = choiceCtrBits;
-
- params->BTBEntries = BTBEntries;
- params->BTBTagSize = BTBTagSize;
-
- params->RASSize = RASSize;
-
- params->LQEntries = LQEntries;
- params->SQEntries = SQEntries;
-
- params->SSITSize = SSITSize;
- params->LFSTSize = LFSTSize;
-
- params->numPhysIntRegs = numPhysIntRegs;
- params->numPhysFloatRegs = numPhysFloatRegs;
- params->numIQEntries = numIQEntries;
- params->numROBEntries = numROBEntries;
-
- params->smtNumFetchingThreads = smtNumFetchingThreads;
-
- // Default smtFetchPolicy to "RoundRobin", if necessary.
- std::string round_robin_policy = "RoundRobin";
- std::string single_thread = "SingleThread";
-
- if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
- params->smtFetchPolicy = round_robin_policy;
- else
- params->smtFetchPolicy = smtFetchPolicy;
-
- params->smtIQPolicy = smtIQPolicy;
- params->smtLSQPolicy = smtLSQPolicy;
- params->smtLSQThreshold = smtLSQThreshold;
- params->smtROBPolicy = smtROBPolicy;
- params->smtROBThreshold = smtROBThreshold;
- params->smtCommitPolicy = smtCommitPolicy;
-
- params->instShiftAmt = 2;
-
- params->deferRegistration = defer_registration;
-
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
-
- cpu = new DerivO3CPU(params);
-
- return cpu;
-}
diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh
deleted file mode 100644
index 09d73b4a2..000000000
--- a/src/cpu/o3/mips/cpu_impl.hh
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#include "config/use_checker.hh"
-
-#include "arch/mips/faults.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "cpu/checker/thread_context.hh"
-#include "sim/sim_events.hh"
-#include "sim/stats.hh"
-
-#include "cpu/o3/mips/cpu.hh"
-#include "cpu/o3/mips/params.hh"
-#include "cpu/o3/mips/thread_context.hh"
-#include "cpu/o3/comm.hh"
-#include "cpu/o3/thread_state.hh"
-
-template <class Impl>
-MipsO3CPU<Impl>::MipsO3CPU(Params *params)
- : FullO3CPU<Impl>(this, params)
-{
- DPRINTF(O3CPU, "Creating MipsO3CPU object.\n");
-
- // Setup any thread state.
- this->thread.resize(this->numThreads);
-
- for (int i = 0; i < this->numThreads; ++i) {
- if (i < params->workload.size()) {
- DPRINTF(O3CPU, "Workload[%i] process is %#x",
- i, this->thread[i]);
- this->thread[i] = new Thread(this, i, params->workload[i], i);
-
- this->thread[i]->setStatus(ThreadContext::Suspended);
-
- //usedTids[i] = true;
- //threadMap[i] = i;
- } else {
- //Allocate Empty thread so M5 can use later
- //when scheduling threads to CPU
- Process* dummy_proc = NULL;
-
- this->thread[i] = new Thread(this, i, dummy_proc, i);
- //usedTids[i] = false;
- }
-
- ThreadContext *tc;
-
- // Setup the TC that will serve as the interface to the threads/CPU.
- MipsTC<Impl> *mips_tc =
- new MipsTC<Impl>;
-
- tc = mips_tc;
-
- // If we're using a checker, then the TC should be the
- // CheckerThreadContext.
-#if USE_CHECKER
- if (params->checker) {
- tc = new CheckerThreadContext<MipsTC<Impl> >(
- mips_tc, this->checker);
- }
-#endif
-
- mips_tc->cpu = this;
- mips_tc->thread = this->thread[i];
-
- // Give the thread the TC.
- this->thread[i]->tc = tc;
- this->thread[i]->setCpuId(params->cpu_id);
-
- // Add the TC to the CPU's list of TC's.
- this->threadContexts.push_back(tc);
- }
-
- for (int i=0; i < this->numThreads; i++) {
- this->thread[i]->setFuncExeInst(0);
- }
-
- lockAddr = 0;
- lockFlag = false;
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::regStats()
-{
- // Register stats for everything that has stats.
- this->fullCPURegStats();
- this->fetch.regStats();
- this->decode.regStats();
- this->rename.regStats();
- this->iew.regStats();
- this->commit.regStats();
-}
-
-
-template <class Impl>
-MiscReg
-MipsO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscRegNoEffect(misc_reg, tid);
-}
-
-template <class Impl>
-MiscReg
-MipsO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscReg(misc_reg, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val,
- unsigned tid)
-{
- this->regFile.setMiscReg(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::squashFromTC(unsigned tid)
-{
- this->thread[tid]->inSyscall = true;
- this->commit.generateTCEvent(tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::trap(Fault fault, unsigned tid)
-{
- // Pass the thread's TC into the invoke method.
- fault->invoke(this->threadContexts[tid]);
-}
-
-#if !FULL_SYSTEM
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::syscall(int64_t callnum, int tid)
-{
- DPRINTF(O3CPU, "[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);
-
- DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2));
-}
-
-template <class Impl>
-TheISA::IntReg
-MipsO3CPU<Impl>::getSyscallArg(int i, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- return this->readArchIntReg(MipsISA::ArgumentReg[i], tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- this->setArchIntReg(MipsISA::ArgumentReg[i], val, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- TheISA::setSyscallReturn(return_value, this->tcBase(tid));
-}
-#endif
diff --git a/src/cpu/o3/mips/dyn_inst.cc b/src/cpu/o3/mips/dyn_inst.cc
deleted file mode 100755
index 216aa7d2c..000000000
--- a/src/cpu/o3/mips/dyn_inst.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#include "cpu/o3/mips/dyn_inst_impl.hh"
-#include "cpu/o3/mips/impl.hh"
-
-// Force instantiation of MipsDynInst for all the implementations that
-// are needed.
-template class MipsDynInst<MipsSimpleImpl>;
diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh
deleted file mode 100755
index b1a29ccf9..000000000
--- a/src/cpu/o3/mips/dyn_inst.hh
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_DYN_INST_HH__
-#define __CPU_O3_MIPS_DYN_INST_HH__
-
-#include "arch/isa_traits.hh"
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/inst_seq.hh"
-#include "cpu/o3/mips/cpu.hh"
-#include "cpu/o3/mips/impl.hh"
-
-class Packet;
-
-/**
- * Mostly implementation & ISA specific MipsDynInst. As with most
- * other classes in the new CPU model, it is templated on the Impl to
- * allow for passing in of all types, such as the CPU type and the ISA
- * type. The MipsDynInst serves as the primary interface to the CPU
- * for instructions that are executing.
- */
-template <class Impl>
-class MipsDynInst : public BaseDynInst<Impl>
-{
- public:
- /** Typedef for the CPU. */
- typedef typename Impl::O3CPU O3CPU;
-
- /** Logical register index type. */
- typedef TheISA::RegIndex RegIndex;
- /** Integer register index type. */
- typedef TheISA::IntReg IntReg;
- typedef TheISA::FloatReg FloatReg;
- typedef TheISA::FloatRegBits FloatRegBits;
- /** Misc register index type. */
- typedef TheISA::MiscReg MiscReg;
-
- enum {
- MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
- MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
- };
-
- public:
- /** BaseDynInst constructor given a binary instruction. */
- MipsDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a binary instruction. */
- MipsDynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a static inst pointer. */
- MipsDynInst(StaticInstPtr &_staticInst);
-
- /** Executes the instruction.*/
- Fault execute();
-
- /** Initiates the access. Only valid for memory operations. */
- Fault initiateAcc();
-
- /** Completes the access. Only valid for memory operations. */
- Fault completeAcc(PacketPtr pkt);
-
- private:
- /** Initializes variables. */
- void initVars();
-
- public:
- /** Reads a miscellaneous register. */
- /** TODO: Use thread number from argument if given, will probably not work for MIPS MT as is */
- MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0)
- {
- return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- MiscReg readMiscReg(int misc_reg, unsigned tid = 0)
- {
- return this->cpu->readMiscReg(misc_reg, this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0)
- {
- this->instResult.integer = val;
- this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
- }
-
- /** 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 = 0)
- {
- return this->cpu->setMiscReg(misc_reg, val,
- this->threadNumber);
- }
-
-
- /** Calls a syscall. */
- void syscall(int64_t callnum);
-
- public:
-
- // The register accessor methods provide the index of the
- // instruction's operand (e.g., 0 or 1), not the architectural
- // register index, to simplify the implementation of register
- // renaming. We find the architectural register index by indexing
- // into the instruction's own operand index table. Note that a
- // raw pointer to the StaticInst is provided instead of a
- // ref-counted StaticInstPtr to redice overhead. This is fine as
- // long as these methods don't copy the pointer into any long-term
- // storage (which is pretty hard to imagine they would have reason
- // to do).
-
- uint64_t readIntRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readIntReg(this->_srcRegIdx[idx]);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
- int width)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
- }
-
- /** @todo: Make results into arrays so they can handle multiple dest
- * registers.
- */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
- {
- this->cpu->setIntReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
- int width)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val, int width)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg 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.
- */
- TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscReg(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
- {
- this->instResult.integer = val;
- return 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 setMiscRegOperand(const StaticInst *si, int idx,
- const MiscReg &val)
- {
- return this->cpu->setMiscReg(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
- uint64_t readRegOtherThread(int misc_reg)
- {
- panic("MIPS MT not defined for O3 CPU.\n");
- return 0;
- }
-
- void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
- {
- panic("MIPS MT not defined for O3 CPU.\n");
- }
-
- public:
- /** Calculates EA part of a memory instruction. Currently unused,
- * though it may be useful in the future if we want to split
- * memory operations into EA calculation and memory access parts.
- */
- Fault calcEA()
- {
- return this->staticInst->eaCompInst()->execute(this, this->traceData);
- }
-
- /** Does the memory access part of a memory instruction. Currently unused,
- * though it may be useful in the future if we want to split
- * memory operations into EA calculation and memory access parts.
- */
- Fault memAccess()
- {
- return this->staticInst->memAccInst()->execute(this, this->traceData);
- }
-};
-
-#endif // __CPU_O3_MIPS_DYN_INST_HH__
-
diff --git a/src/cpu/o3/mips/dyn_inst_impl.hh b/src/cpu/o3/mips/dyn_inst_impl.hh
deleted file mode 100755
index 7e8697b32..000000000
--- a/src/cpu/o3/mips/dyn_inst_impl.hh
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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
- */
-
-#include "cpu/o3/mips/dyn_inst.hh"
-
-template <class Impl>
-MipsDynInst<Impl>::MipsDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-MipsDynInst<Impl>::MipsDynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-MipsDynInst<Impl>::MipsDynInst(StaticInstPtr &_staticInst)
- : BaseDynInst<Impl>(_staticInst)
-{
- initVars();
-}
-
-template <class Impl>
-void
-MipsDynInst<Impl>::initVars()
-{
- // 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.
- for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
- this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
- }
-
- for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
- this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
- this->_readySrcRegIdx[i] = 0;
- }
-}
-
-template <class Impl>
-Fault
-MipsDynInst<Impl>::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;
-}
-
-template <class Impl>
-Fault
-MipsDynInst<Impl>::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;
-}
-
-template <class Impl>
-Fault
-MipsDynInst<Impl>::completeAcc(PacketPtr pkt)
-{
- this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
-
- return this->fault;
-}
-
-template <class Impl>
-void
-MipsDynInst<Impl>::syscall(int64_t callnum)
-{
- this->cpu->syscall(callnum, this->threadNumber);
-}
-
diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh
deleted file mode 100644
index ac7181a19..000000000
--- a/src/cpu/o3/mips/impl.hh
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_IMPL_HH__
-#define __CPU_O3_MIPS_IMPL_HH__
-
-#include "arch/mips/isa_traits.hh"
-
-#include "cpu/o3/mips/params.hh"
-#include "cpu/o3/cpu_policy.hh"
-
-
-// Forward declarations.
-template <class Impl>
-class MipsDynInst;
-
-template <class Impl>
-class MipsO3CPU;
-
-/** Implementation specific struct that defines several key types to the
- * CPU, the stages within the CPU, the time buffers, and the DynInst.
- * The struct defines the ISA, the CPU policy, the specific DynInst, the
- * specific O3CPU, and all of the structs from the time buffers to do
- * communication.
- * This is one of the key things that must be defined for each hardware
- * specific CPU implementation.
- */
-struct MipsSimpleImpl
-{
- /** The type of MachInst. */
- typedef TheISA::MachInst MachInst;
-
- /** The CPU policy to be used, which defines all of the CPU stages. */
- typedef SimpleCPUPolicy<MipsSimpleImpl> CPUPol;
-
- /** The DynInst type to be used. */
- typedef MipsDynInst<MipsSimpleImpl> DynInst;
-
- /** The refcounted DynInst pointer to be used. In most cases this is
- * what should be used, and not DynInst *.
- */
- typedef RefCountingPtr<DynInst> DynInstPtr;
-
- /** The O3CPU type to be used. */
- typedef MipsO3CPU<MipsSimpleImpl> O3CPU;
-
- /** Same typedef, but for CPUType. BaseDynInst may not always use
- * an O3 CPU, so it's clearer to call it CPUType instead in that
- * case.
- */
- typedef O3CPU CPUType;
-
- /** The Params to be passed to each stage. */
- typedef MipsSimpleParams Params;
-
- enum {
- MaxWidth = 8,
- MaxThreads = 4
- };
-};
-
-/** The O3Impl to be used. */
-typedef MipsSimpleImpl O3CPUImpl;
-
-#endif // __CPU_O3_MIPS_IMPL_HH__
diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh
index 97846ed16..f0621c5b5 100644
--- a/src/cpu/o3/ras.hh
+++ b/src/cpu/o3/ras.hh
@@ -71,6 +71,9 @@ class ReturnAddrStack
*/
void restore(unsigned top_entry_idx, const Addr &restored_target);
+ bool empty() { return usedEntries == 0; }
+
+ bool full() { return usedEntries == numEntries; }
private:
/** Increments the top of stack index. */
inline void incrTos()
diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh
index 75d3fa6eb..53ac2d683 100644
--- a/src/cpu/o3/regfile.hh
+++ b/src/cpu/o3/regfile.hh
@@ -33,6 +33,7 @@
#define __CPU_O3_REGFILE_HH__
#include "arch/isa_traits.hh"
+#include "arch/regfile.hh"
#include "arch/types.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
@@ -264,7 +265,7 @@ class PhysRegFile
#if FULL_SYSTEM
private:
- int intrflag; // interrupt flag
+ int intrflag; // interrupt flag
#endif
private:
diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh
index b2faffe43..0fdf28b19 100644
--- a/src/cpu/o3/rename.hh
+++ b/src/cpu/o3/rename.hh
@@ -36,6 +36,8 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
+class DerivO3CPUParams;
+
/**
* DefaultRename handles both single threaded and SMT rename. Its
* width is specified by the parameters; each cycle it tries to rename
@@ -56,7 +58,6 @@ class DefaultRename
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
// Typedefs from the CPUPol
typedef typename CPUPol::DecodeStruct DecodeStruct;
@@ -107,7 +108,7 @@ class DefaultRename
public:
/** DefaultRename constructor. */
- DefaultRename(O3CPU *_cpu, Params *params);
+ DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of rename. */
std::string name() const;
@@ -440,44 +441,44 @@ class DefaultRename
inline void incrFullStat(const FullSource &source);
/** Stat for total number of cycles spent squashing. */
- Stats::Scalar<> renameSquashCycles;
+ Stats::Scalar renameSquashCycles;
/** Stat for total number of cycles spent idle. */
- Stats::Scalar<> renameIdleCycles;
+ Stats::Scalar renameIdleCycles;
/** Stat for total number of cycles spent blocking. */
- Stats::Scalar<> renameBlockCycles;
+ Stats::Scalar renameBlockCycles;
/** Stat for total number of cycles spent stalling for a serializing inst. */
- Stats::Scalar<> renameSerializeStallCycles;
+ Stats::Scalar renameSerializeStallCycles;
/** Stat for total number of cycles spent running normally. */
- Stats::Scalar<> renameRunCycles;
+ Stats::Scalar renameRunCycles;
/** Stat for total number of cycles spent unblocking. */
- Stats::Scalar<> renameUnblockCycles;
+ Stats::Scalar renameUnblockCycles;
/** Stat for total number of renamed instructions. */
- Stats::Scalar<> renameRenamedInsts;
+ Stats::Scalar renameRenamedInsts;
/** Stat for total number of squashed instructions that rename discards. */
- Stats::Scalar<> renameSquashedInsts;
+ Stats::Scalar renameSquashedInsts;
/** Stat for total number of times that the ROB starts a stall in rename. */
- Stats::Scalar<> renameROBFullEvents;
+ Stats::Scalar renameROBFullEvents;
/** Stat for total number of times that the IQ starts a stall in rename. */
- Stats::Scalar<> renameIQFullEvents;
+ Stats::Scalar renameIQFullEvents;
/** Stat for total number of times that the LSQ starts a stall in rename. */
- Stats::Scalar<> renameLSQFullEvents;
+ Stats::Scalar renameLSQFullEvents;
/** Stat for total number of times that rename runs out of free registers
* to use to rename. */
- Stats::Scalar<> renameFullRegistersEvents;
+ Stats::Scalar renameFullRegistersEvents;
/** Stat for total number of renamed destination registers. */
- Stats::Scalar<> renameRenamedOperands;
+ Stats::Scalar renameRenamedOperands;
/** Stat for total number of source register rename lookups. */
- Stats::Scalar<> renameRenameLookups;
+ Stats::Scalar renameRenameLookups;
/** Stat for total number of committed renaming mappings. */
- Stats::Scalar<> renameCommittedMaps;
+ Stats::Scalar renameCommittedMaps;
/** Stat for total number of mappings that were undone due to a squash. */
- Stats::Scalar<> renameUndoneMaps;
+ Stats::Scalar renameUndoneMaps;
/** Number of serialize instructions handled. */
- Stats::Scalar<> renamedSerializing;
+ Stats::Scalar renamedSerializing;
/** Number of instructions marked as temporarily serializing. */
- Stats::Scalar<> renamedTempSerializing;
+ Stats::Scalar renamedTempSerializing;
/** Number of instructions inserted into skid buffers. */
- Stats::Scalar<> renameSkidInsts;
+ Stats::Scalar renameSkidInsts;
};
#endif // __CPU_O3_RENAME_HH__
diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh
index 49c885753..81647b133 100644
--- a/src/cpu/o3/rename_impl.hh
+++ b/src/cpu/o3/rename_impl.hh
@@ -35,9 +35,10 @@
#include "arch/regfile.hh"
#include "config/full_system.hh"
#include "cpu/o3/rename.hh"
+#include "params/DerivO3CPU.hh"
template <class Impl>
-DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params)
+DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
iewToRenameDelay(params->iewToRenameDelay),
decodeToRenameDelay(params->decodeToRenameDelay),
@@ -46,7 +47,7 @@ DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params)
commitWidth(params->commitWidth),
resumeSerialize(false),
resumeUnblocking(false),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs)
{
_status = Inactive;
diff --git a/src/cpu/o3/sparc/cpu.cc b/src/cpu/o3/sparc/cpu.cc
deleted file mode 100644
index 1546a2b88..000000000
--- a/src/cpu/o3/sparc/cpu.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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: Gabe Black
- */
-
-#include "cpu/o3/sparc/impl.hh"
-#include "cpu/o3/sparc/cpu_impl.hh"
-#include "cpu/o3/sparc/dyn_inst.hh"
-
-// Force instantiation of SparcO3CPU for all the implementations that are
-// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all
-// classes that depend on a certain impl, into one file (sparc_impl.cc?).
-template class SparcO3CPU<SparcSimpleImpl>;
diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh
deleted file mode 100644
index 3fd193e0f..000000000
--- a/src/cpu/o3/sparc/cpu.hh
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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
- */
-
-#ifndef __CPU_O3_SPARC_CPU_HH__
-#define __CPU_O3_SPARC_CPU_HH__
-
-#include "arch/sparc/regfile.hh"
-#include "arch/sparc/types.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/o3/cpu.hh"
-#include "sim/byteswap.hh"
-
-class EndQuiesceEvent;
-namespace Kernel {
- class Statistics;
-};
-
-class TranslatingPort;
-
-/**
- * SparcO3CPU class. Derives from the FullO3CPU class, and
- * implements all ISA and implementation specific functions of the
- * CPU. This is the CPU class that is used for the SimObjects, and is
- * what is given to the DynInsts. Most of its state exists in the
- * FullO3CPU; the state is has is mainly for ISA specific
- * functionality.
- */
-template <class Impl>
-class SparcO3CPU : public FullO3CPU<Impl>
-{
- public:
- typedef O3ThreadState<Impl> ImplState;
- typedef O3ThreadState<Impl> Thread;
- typedef typename Impl::Params Params;
-
- /** Constructs an AlphaO3CPU with the given parameters. */
- SparcO3CPU(Params *params);
-
- /** Registers statistics. */
- void regStats();
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
-
- /** Reads a misc. register, including any side effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::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 TheISA::MiscReg &val,
- unsigned tid);
-
- /** Initiates a squash of all in-flight instructions for a given
- * thread. The source of the squash is an external update of
- * state through the TC.
- */
- void squashFromTC(unsigned tid);
-
-#if FULL_SYSTEM
- /** Posts an interrupt. */
- void post_interrupt(int int_num, int index);
- /** HW return from error interrupt. */
- Fault hwrei(unsigned tid);
-
- bool simPalCheck(int palFunc, unsigned tid);
-
- /** Returns the Fault for any valid interrupt. */
- Fault getInterrupts();
-
- /** Processes any an interrupt fault. */
- void processInterrupts(Fault interrupt);
-
- /** Halts the CPU. */
- void halt() { panic("Halt not implemented!\n"); }
-#endif
-
- /** Traps to handle given fault. */
- void trap(Fault fault, unsigned tid);
-
-#if !FULL_SYSTEM
- /** Executes a syscall.
- * @todo: Determine if this needs to be virtual.
- */
- void syscall(int64_t callnum, int tid);
- /** Gets a syscall argument. */
- TheISA::IntReg getSyscallArg(int i, int tid);
-
- /** Used to shift args for indirect syscall. */
- void setSyscallArg(int i, TheISA::IntReg val, int tid);
-
- /** Sets the return value of a syscall. */
- void setSyscallReturn(SyscallReturn return_value, int tid);
-#endif
-
- /** CPU read function, forwards read to LSQ. */
- template <class T>
- Fault read(RequestPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- /** CPU write function, forwards write to LSQ. */
- template <class T>
- Fault write(RequestPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
- Addr lockAddr;
-
- /** Temporary fix for the lock flag, works in the UP case. */
- bool lockFlag;
-};
-
-#endif // __CPU_O3_SPARC_CPU_HH__
diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc
deleted file mode 100644
index b08845b4e..000000000
--- a/src/cpu/o3/sparc/cpu_builder.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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: Gabe Black
- */
-
-#include <string>
-
-#include "config/full_system.hh"
-#include "config/use_checker.hh"
-#include "cpu/base.hh"
-#include "cpu/o3/sparc/cpu.hh"
-#include "cpu/o3/sparc/impl.hh"
-#include "cpu/o3/sparc/params.hh"
-#include "cpu/o3/fu_pool.hh"
-#include "params/DerivO3CPU.hh"
-
-class DerivO3CPU : public SparcO3CPU<SparcSimpleImpl>
-{
- public:
- DerivO3CPU(SparcSimpleParams *p)
- : SparcO3CPU<SparcSimpleImpl>(p)
- { }
-};
-
-DerivO3CPU *
-DerivO3CPUParams::create()
-{
- DerivO3CPU *cpu;
-
-#if FULL_SYSTEM
- // Full-system only supports a single thread for the moment.
- int actual_num_threads = 1;
-#else
- // In non-full-system mode, we infer the number of threads from
- // the workload if it's not explicitly specified.
- int actual_num_threads =
- (numThreads >= workload.size()) ? numThreads : workload.size();
-
- if (workload.size() == 0) {
- fatal("Must specify at least one workload!");
- }
-#endif
-
- SparcSimpleParams *params = new SparcSimpleParams;
-
- params->clock = clock;
- params->phase = phase;
-
- params->tracer = tracer;
-
- params->name = name;
- params->numberOfThreads = actual_num_threads;
- params->cpu_id = cpu_id;
- params->activity = activity;
-
- params->itb = itb;
- params->dtb = dtb;
-
- params->system = system;
-#if FULL_SYSTEM
- params->profile = profile;
-
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
- params->workload = workload;
-#endif // FULL_SYSTEM
-
-#if USE_CHECKER
- params->checker = checker;
-#endif
-
- params->max_insts_any_thread = max_insts_any_thread;
- params->max_insts_all_threads = max_insts_all_threads;
- params->max_loads_any_thread = max_loads_any_thread;
- params->max_loads_all_threads = max_loads_all_threads;
- params->progress_interval = progress_interval;
-
- //
- // Caches
- //
- params->cachePorts = cachePorts;
-
- params->decodeToFetchDelay = decodeToFetchDelay;
- params->renameToFetchDelay = renameToFetchDelay;
- params->iewToFetchDelay = iewToFetchDelay;
- params->commitToFetchDelay = commitToFetchDelay;
- params->fetchWidth = fetchWidth;
-
- params->renameToDecodeDelay = renameToDecodeDelay;
- params->iewToDecodeDelay = iewToDecodeDelay;
- params->commitToDecodeDelay = commitToDecodeDelay;
- params->fetchToDecodeDelay = fetchToDecodeDelay;
- params->decodeWidth = decodeWidth;
-
- params->iewToRenameDelay = iewToRenameDelay;
- params->commitToRenameDelay = commitToRenameDelay;
- params->decodeToRenameDelay = decodeToRenameDelay;
- params->renameWidth = renameWidth;
-
- params->commitToIEWDelay = commitToIEWDelay;
- params->renameToIEWDelay = renameToIEWDelay;
- params->issueToExecuteDelay = issueToExecuteDelay;
- params->dispatchWidth = dispatchWidth;
- params->issueWidth = issueWidth;
- params->wbWidth = wbWidth;
- params->wbDepth = wbDepth;
- params->fuPool = fuPool;
-
- params->iewToCommitDelay = iewToCommitDelay;
- params->renameToROBDelay = renameToROBDelay;
- params->commitWidth = commitWidth;
- params->squashWidth = squashWidth;
- params->trapLatency = trapLatency;
-
- params->backComSize = backComSize;
- params->forwardComSize = forwardComSize;
-
- params->predType = predType;
- params->localPredictorSize = localPredictorSize;
- params->localCtrBits = localCtrBits;
- params->localHistoryTableSize = localHistoryTableSize;
- params->localHistoryBits = localHistoryBits;
- params->globalPredictorSize = globalPredictorSize;
- params->globalCtrBits = globalCtrBits;
- params->globalHistoryBits = globalHistoryBits;
- params->choicePredictorSize = choicePredictorSize;
- params->choiceCtrBits = choiceCtrBits;
-
- params->BTBEntries = BTBEntries;
- params->BTBTagSize = BTBTagSize;
-
- params->RASSize = RASSize;
-
- params->LQEntries = LQEntries;
- params->SQEntries = SQEntries;
-
- params->SSITSize = SSITSize;
- params->LFSTSize = LFSTSize;
-
- params->numPhysIntRegs = numPhysIntRegs;
- params->numPhysFloatRegs = numPhysFloatRegs;
- params->numIQEntries = numIQEntries;
- params->numROBEntries = numROBEntries;
-
- params->smtNumFetchingThreads = smtNumFetchingThreads;
-
- // Default smtFetchPolicy to "RoundRobin", if necessary.
- std::string round_robin_policy = "RoundRobin";
- std::string single_thread = "SingleThread";
-
- if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
- params->smtFetchPolicy = round_robin_policy;
- else
- params->smtFetchPolicy = smtFetchPolicy;
-
- params->smtIQPolicy = smtIQPolicy;
- params->smtLSQPolicy = smtLSQPolicy;
- params->smtLSQThreshold = smtLSQThreshold;
- params->smtROBPolicy = smtROBPolicy;
- params->smtROBThreshold = smtROBThreshold;
- params->smtCommitPolicy = smtCommitPolicy;
-
- params->instShiftAmt = 2;
-
- params->deferRegistration = defer_registration;
-
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
-
- cpu = new DerivO3CPU(params);
-
- return cpu;
-}
diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh
deleted file mode 100644
index 068057fc0..000000000
--- a/src/cpu/o3/sparc/cpu_impl.hh
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * 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: Gabe Black
- */
-
-#include "config/use_checker.hh"
-
-#include "arch/sparc/faults.hh"
-#include "arch/sparc/isa_traits.hh"
-#include "arch/sparc/miscregfile.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "cpu/checker/thread_context.hh"
-#include "sim/sim_events.hh"
-#include "sim/stats.hh"
-
-#include "cpu/o3/sparc/cpu.hh"
-#include "cpu/o3/sparc/params.hh"
-#include "cpu/o3/sparc/thread_context.hh"
-#include "cpu/o3/comm.hh"
-#include "cpu/o3/thread_state.hh"
-
-#if FULL_SYSTEM
-#include "arch/sparc/isa_traits.hh"
-#include "arch/sparc/kernel_stats.hh"
-#include "cpu/quiesce_event.hh"
-#include "sim/sim_exit.hh"
-#include "sim/system.hh"
-#endif
-
-template <class Impl>
-SparcO3CPU<Impl>::SparcO3CPU(Params *params) : FullO3CPU<Impl>(this, params)
-{
- DPRINTF(O3CPU, "Creating SparcO3CPU object.\n");
-
- // Setup any thread state.
- this->thread.resize(this->numThreads);
-
- for (int i = 0; i < this->numThreads; ++i) {
-#if FULL_SYSTEM
- // SMT is not supported in FS mode yet.
- assert(this->numThreads == 1);
- this->thread[i] = new Thread(this, 0);
- this->thread[i]->setStatus(ThreadContext::Suspended);
-#else
- if (i < params->workload.size()) {
- DPRINTF(O3CPU, "Workload[%i] process is %#x",
- i, this->thread[i]);
- this->thread[i] = new Thread(this, i, params->workload[i], i);
-
- this->thread[i]->setStatus(ThreadContext::Suspended);
-
- //usedTids[i] = true;
- //threadMap[i] = i;
- } else {
- //Allocate Empty thread so M5 can use later
- //when scheduling threads to CPU
- Process* dummy_proc = NULL;
-
- this->thread[i] = new Thread(this, i, dummy_proc, i);
- //usedTids[i] = false;
- }
-#endif // !FULL_SYSTEM
-
- ThreadContext *tc;
-
- // Setup the TC that will serve as the interface to the threads/CPU.
- SparcTC<Impl> *sparc_tc = new SparcTC<Impl>;
-
- tc = sparc_tc;
-
- // If we're using a checker, then the TC should be the
- // CheckerThreadContext.
-#if USE_CHECKER
- if (params->checker) {
- tc = new CheckerThreadContext<SparcTC<Impl> >(
- sparc_tc, this->checker);
- }
-#endif
-
- sparc_tc->cpu = this;
- sparc_tc->thread = this->thread[i];
-
-#if FULL_SYSTEM
- // Setup quiesce event.
- this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc);
-#endif
- // Give the thread the TC.
- this->thread[i]->tc = tc;
- this->thread[i]->setCpuId(params->cpu_id);
-
- // Add the TC to the CPU's list of TC's.
- this->threadContexts.push_back(tc);
- }
-
- for (int i=0; i < this->numThreads; i++) {
- this->thread[i]->setFuncExeInst(0);
- }
-
- lockAddr = 0;
- lockFlag = false;
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::regStats()
-{
- // Register stats for everything that has stats.
- this->fullCPURegStats();
- this->fetch.regStats();
- this->decode.regStats();
- this->rename.regStats();
- this->iew.regStats();
- this->commit.regStats();
-}
-
-
-template <class Impl>
-TheISA::MiscReg
-SparcO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscRegNoEffect(misc_reg, tid);
-}
-
-template <class Impl>
-TheISA::MiscReg
-SparcO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscReg(misc_reg, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setMiscRegNoEffect(int misc_reg,
- const SparcISA::MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setMiscReg(int misc_reg,
- const SparcISA::MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscReg(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::squashFromTC(unsigned tid)
-{
- this->thread[tid]->inSyscall = true;
- this->commit.generateTCEvent(tid);
-}
-
-#if FULL_SYSTEM
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::post_interrupt(int int_num, int index)
-{
- BaseCPU::post_interrupt(int_num, index);
-
- if (this->thread[0]->status() == ThreadContext::Suspended) {
- DPRINTF(IPI,"Suspended Processor awoke\n");
- this->threadContexts[0]->activate();
- }
-}
-
-template <class Impl>
-Fault
-SparcO3CPU<Impl>::hwrei(unsigned tid)
-{
- panic("This doesn't make sense for SPARC\n");
- return NoFault;
-}
-
-template <class Impl>
-bool
-SparcO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid)
-{
- panic("This doesn't make sense for SPARC\n");
- return true;
-}
-
-template <class Impl>
-Fault
-SparcO3CPU<Impl>::getInterrupts()
-{
- // Check if there are any outstanding interrupts
- return this->interrupts.getInterrupt(this->threadContexts[0]);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::processInterrupts(Fault interrupt)
-{
- // Check for interrupts here. For now can copy the code that
- // exists within isa_fullsys_traits.hh. Also assume that thread 0
- // is the one that handles the interrupts.
- // @todo: Possibly consolidate the interrupt checking code.
- // @todo: Allow other threads to handle interrupts.
-
- assert(interrupt != NoFault);
- this->interrupts.updateIntrInfo(this->threadContexts[0]);
-
- DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
- this->trap(interrupt, 0);
-}
-
-#endif // FULL_SYSTEM
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::trap(Fault fault, unsigned tid)
-{
- // Pass the thread's TC into the invoke method.
- fault->invoke(this->threadContexts[tid]);
-}
-
-#if !FULL_SYSTEM
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::syscall(int64_t callnum, int tid)
-{
- DPRINTF(O3CPU, "[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);
-}
-
-template <class Impl>
-TheISA::IntReg
-SparcO3CPU<Impl>::getSyscallArg(int i, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid),
- SparcISA::ArgumentReg[i]);
- TheISA::IntReg val = this->readArchIntReg(idx, tid);
- if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3))
- val = bits(val, 31, 0);
- return val;
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid),
- SparcISA::ArgumentReg[i]);
- this->setArchIntReg(idx, val, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- TheISA::setSyscallReturn(return_value, this->tcBase(tid));
-}
-#endif
diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh
deleted file mode 100644
index a7ab6cd79..000000000
--- a/src/cpu/o3/sparc/dyn_inst.hh
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * 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: Gabe Black
- */
-
-#ifndef __CPU_O3_SPARC_DYN_INST_HH__
-#define __CPU_O3_SPARC_DYN_INST_HH__
-
-#include "arch/sparc/isa_traits.hh"
-#include "arch/sparc/types.hh"
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/inst_seq.hh"
-#include "cpu/o3/sparc/cpu.hh"
-#include "cpu/o3/sparc/impl.hh"
-
-class Packet;
-
-/**
- * Mostly implementation & ISA specific SparcDynInst. As with most
- * other classes in the new CPU model, it is templated on the Impl to
- * allow for passing in of all types, such as the CPU type and the ISA
- * type. The SparcDynInst serves as the primary interface to the CPU
- * for instructions that are executing.
- */
-template <class Impl>
-class SparcDynInst : public BaseDynInst<Impl>
-{
- public:
- /** Typedef for the CPU. */
- typedef typename Impl::O3CPU O3CPU;
-
- public:
- /** BaseDynInst constructor given a binary instruction. */
- SparcDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a binary instruction. */
- SparcDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a static inst pointer. */
- SparcDynInst(StaticInstPtr &_staticInst);
-
- /** Executes the instruction.*/
- Fault execute();
-
- /** Initiates the access. Only valid for memory operations. */
- Fault initiateAcc();
-
- /** Completes the access. Only valid for memory operations. */
- Fault completeAcc(PacketPtr pkt);
-
- private:
- /** Initializes variables. */
- void initVars();
-
- public:
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg)
- {
- return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg)
- {
- return this->cpu->readMiscReg(misc_reg, this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg, const TheISA::MiscReg &val)
- {
- return this->cpu->setMiscReg(misc_reg, val,
- this->threadNumber);
- }
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg 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.
- */
- TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscReg(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegOperandNoEffect(const StaticInst * si,
- int idx, const TheISA::MiscReg &val)
- {
- this->instResult.integer = val;
- return 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 setMiscRegOperand(
- const StaticInst *si, int idx, const TheISA::MiscReg &val)
- {
- return this->cpu->setMiscReg(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
-#if FULL_SYSTEM
- /** Calls hardware return from error interrupt. */
- Fault hwrei();
- /** Traps to handle specified fault. */
- void trap(Fault fault);
- bool simPalCheck(int palFunc);
-#else
- /** Calls a syscall. */
- void syscall(int64_t callnum);
-#endif
-
- public:
-
- // The register accessor methods provide the index of the
- // instruction's operand (e.g., 0 or 1), not the architectural
- // register index, to simplify the implementation of register
- // renaming. We find the architectural register index by indexing
- // into the instruction's own operand index table. Note that a
- // raw pointer to the StaticInst is provided instead of a
- // ref-counted StaticInstPtr to redice overhead. This is fine as
- // long as these methods don't copy the pointer into any long-term
- // storage (which is pretty hard to imagine they would have reason
- // to do).
-
- uint64_t readIntRegOperand(const StaticInst *si, int idx)
- {
- uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]);
- DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val);
- return val;
- }
-
- TheISA::FloatReg readFloatRegOperand(const StaticInst *si,
- int idx, int width)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
- }
-
- TheISA::FloatReg readFloatRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
- }
-
- TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si,
- int idx, int width)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
- }
-
- TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
- }
-
- /** @todo: Make results into arrays so they can handle multiple dest
- * registers.
- */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
- {
- DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val);
- this->cpu->setIntReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx,
- TheISA::FloatReg val, int width)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, TheISA::FloatReg val)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- TheISA::FloatRegBits val, int width)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si,
- int idx, TheISA::FloatRegBits val)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- public:
- /** Calculates EA part of a memory instruction. Currently unused,
- * though it may be useful in the future if we want to split
- * memory operations into EA calculation and memory access parts.
- */
- Fault calcEA()
- {
- return this->staticInst->eaCompInst()->execute(this, this->traceData);
- }
-
- /** Does the memory access part of a memory instruction. Currently unused,
- * though it may be useful in the future if we want to split
- * memory operations into EA calculation and memory access parts.
- */
- Fault memAccess()
- {
- return this->staticInst->memAccInst()->execute(this, this->traceData);
- }
-};
-
-#endif // __CPU_O3_SPARC_DYN_INST_HH__
-
diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh
deleted file mode 100644
index 6bfe97717..000000000
--- a/src/cpu/o3/sparc/dyn_inst_impl.hh
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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: Gabe Black
- */
-
-#include "cpu/o3/sparc/dyn_inst.hh"
-
-template <class Impl>
-SparcDynInst<Impl>::SparcDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-SparcDynInst<Impl>::SparcDynInst(StaticInstPtr &_staticInst)
- : BaseDynInst<Impl>(_staticInst)
-{
- initVars();
-}
-
-template <class Impl>
-void
-SparcDynInst<Impl>::initVars()
-{
- // 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.
- for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
- this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
- }
-
- for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
- this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
- this->_readySrcRegIdx[i] = 0;
- }
-}
-
-template <class Impl>
-Fault
-SparcDynInst<Impl>::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;
-}
-
-template <class Impl>
-Fault
-SparcDynInst<Impl>::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;
-}
-
-template <class Impl>
-Fault
-SparcDynInst<Impl>::completeAcc(PacketPtr pkt)
-{
- this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
-
- return this->fault;
-}
-
-#if FULL_SYSTEM
-template <class Impl>
-Fault
-SparcDynInst<Impl>::hwrei()
-{
- return NoFault;
-}
-
-template <class Impl>
-void
-SparcDynInst<Impl>::trap(Fault fault)
-{
- this->cpu->trap(fault, this->threadNumber);
-}
-
-template <class Impl>
-bool
-SparcDynInst<Impl>::simPalCheck(int palFunc)
-{
- panic("simPalCheck called, but there's no PAL in SPARC!\n");
- return false;
-}
-#else
-template <class Impl>
-void
-SparcDynInst<Impl>::syscall(int64_t callnum)
-{
- this->cpu->syscall(callnum, this->threadNumber);
-}
-#endif
-
diff --git a/src/cpu/o3/alpha/thread_context.cc b/src/cpu/o3/thread_context.cc
index 4a02715bc..0d8c67643 100755
--- a/src/cpu/o3/alpha/thread_context.cc
+++ b/src/cpu/o3/thread_context.cc
@@ -26,11 +26,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
- * Korey Sewell
*/
#include "cpu/o3/thread_context.hh"
#include "cpu/o3/thread_context_impl.hh"
+#include "cpu/o3/impl.hh"
-template class O3ThreadContext<AlphaSimpleImpl>;
+template class O3ThreadContext<O3CPUImpl>;
diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh
index e7bdc6de5..f3058925d 100755
--- a/src/cpu/o3/thread_context.hh
+++ b/src/cpu/o3/thread_context.hh
@@ -75,16 +75,21 @@ class O3ThreadContext : public ThreadContext
/** Returns a pointer to this CPU. */
virtual BaseCPU *getCpuPtr() { return cpu; }
- /** Sets this CPU's ID. */
- virtual void setCpuId(int id) { cpu->setCpuId(id); }
-
/** Reads this CPU's ID. */
- virtual int readCpuId() { return cpu->readCpuId(); }
+ 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); }
-#if FULL_SYSTEM
/** Returns a pointer to the system. */
virtual System *getSystemPtr() { return cpu->system; }
+#if FULL_SYSTEM
/** Returns a pointer to physical memory. */
virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; }
@@ -94,11 +99,9 @@ class O3ThreadContext : public ThreadContext
virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); }
- virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL);
-
- void delVirtPort(VirtualPort *vp);
+ virtual VirtualPort *getVirtPort();
- virtual void connectMemPorts() { thread->connectMemPorts(); }
+ virtual void connectMemPorts(ThreadContext *tc) { thread->connectMemPorts(tc); }
#else
virtual TranslatingPort *getMemPort() { return thread->getMemPort(); }
@@ -153,9 +156,6 @@ class O3ThreadContext : public ThreadContext
/** Samples the function profiling information. */
virtual void profileSample();
#endif
- /** 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.
*/
@@ -191,36 +191,36 @@ class O3ThreadContext : public ThreadContext
/** Reads this thread's PC. */
virtual uint64_t readPC()
- { return cpu->readPC(thread->readTid()); }
+ { return cpu->readPC(thread->threadId()); }
/** 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()); }
+ { return cpu->readNextPC(thread->threadId()); }
/** Sets this thread's next PC. */
virtual void setNextPC(uint64_t val);
virtual uint64_t readMicroPC()
- { return cpu->readMicroPC(thread->readTid()); }
+ { return cpu->readMicroPC(thread->threadId()); }
virtual void setMicroPC(uint64_t val);
virtual uint64_t readNextMicroPC()
- { return cpu->readNextMicroPC(thread->readTid()); }
+ { return cpu->readNextMicroPC(thread->threadId()); }
virtual void setNextMicroPC(uint64_t val);
/** Reads a miscellaneous register. */
virtual MiscReg readMiscRegNoEffect(int misc_reg)
- { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); }
+ { return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); }
/** 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()); }
+ { return cpu->readMiscReg(misc_reg, thread->threadId()); }
/** Sets a misc. register. */
virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
@@ -247,22 +247,48 @@ class O3ThreadContext : public ThreadContext
virtual bool misspeculating() { return false; }
#if !FULL_SYSTEM
- /** 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()); }
+ { return cpu->syscall(callnum, thread->threadId()); }
/** Reads the funcExeInst counter. */
virtual Counter readFuncExeInst() { return thread->funcExeInst; }
+#else
+ /** Returns pointer to the quiesce event. */
+ virtual EndQuiesceEvent *getQuiesceEvent()
+ {
+ return this->thread->quiesceEvent;
+ }
#endif
+
+ virtual uint64_t readNextNPC()
+ {
+ return this->cpu->readNextNPC(this->thread->threadId());
+ }
+
+ virtual void setNextNPC(uint64_t val)
+ {
+#if THE_ISA == ALPHA_ISA
+ panic("Not supported on Alpha!");
+#endif
+ this->cpu->setNextNPC(val, this->thread->threadId());
+ }
+
+ /** 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
+ if (this->cpu->numActiveThreads())
+ return 0; // don't exit simulation
+ else
+ return 1; // exit simulation
+ }
};
#endif
diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh
index 865d58635..fc8b66b83 100755
--- a/src/cpu/o3/thread_context_impl.hh
+++ b/src/cpu/o3/thread_context_impl.hh
@@ -36,16 +36,9 @@
#if FULL_SYSTEM
template <class Impl>
VirtualPort *
-O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc)
+O3ThreadContext<Impl>::getVirtPort()
{
- if (!src_tc)
- return thread->getVirtPort();
-
- VirtualPort *vp;
-
- vp = new VirtualPort("tc-vport", src_tc);
- thread->connectToMemFunc(vp);
- return vp;
+ return thread->getVirtPort();
}
template <class Impl>
@@ -61,16 +54,16 @@ void
O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
{
// some things should already be set up
-#if FULL_SYSTEM
assert(getSystemPtr() == old_context->getSystemPtr());
-#else
+#if !FULL_SYSTEM
assert(getProcessPtr() == old_context->getProcessPtr());
#endif
// copy over functional state
setStatus(old_context->status());
copyArchRegs(old_context);
- setCpuId(old_context->readCpuId());
+ setContextId(old_context->contextId());
+ setThreadId(old_context->threadId());
#if !FULL_SYSTEM
thread->funcExeInst = old_context->readFuncExeInst();
@@ -97,24 +90,12 @@ O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
thread->trapPending = false;
}
-#if FULL_SYSTEM
-template <class Impl>
-void
-O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp)
-{
- if (vp != thread->getVirtPort()) {
- vp->removeConn();
- delete vp;
- }
-}
-#endif
-
template <class Impl>
void
O3ThreadContext<Impl>::activate(int delay)
{
DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
- getThreadNum());
+ threadId());
if (thread->status() == ThreadContext::Active)
return;
@@ -124,14 +105,14 @@ O3ThreadContext<Impl>::activate(int delay)
#endif
if (thread->status() == ThreadContext::Unallocated) {
- cpu->activateWhenReady(thread->readTid());
+ cpu->activateWhenReady(thread->threadId());
return;
}
thread->setStatus(ThreadContext::Active);
// status() == Suspended
- cpu->activateContext(thread->readTid(), delay);
+ cpu->activateContext(thread->threadId(), delay);
}
template <class Impl>
@@ -139,7 +120,7 @@ void
O3ThreadContext<Impl>::suspend(int delay)
{
DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
- getThreadNum());
+ threadId());
if (thread->status() == ThreadContext::Suspended)
return;
@@ -151,14 +132,14 @@ O3ThreadContext<Impl>::suspend(int delay)
/*
#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
- if (cpu->check_interrupts()) {
+ if (cpu->checkInterrupts()) {
assert(status() == ThreadContext::Active);
return;
}
#endif
*/
thread->setStatus(ThreadContext::Suspended);
- cpu->suspendContext(thread->readTid());
+ cpu->suspendContext(thread->threadId());
}
template <class Impl>
@@ -166,13 +147,13 @@ void
O3ThreadContext<Impl>::deallocate(int delay)
{
DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n",
- getThreadNum(), delay);
+ threadId(), delay);
if (thread->status() == ThreadContext::Unallocated)
return;
thread->setStatus(ThreadContext::Unallocated);
- cpu->deallocateContext(thread->readTid(), true, delay);
+ cpu->deallocateContext(thread->threadId(), true, delay);
}
template <class Impl>
@@ -180,13 +161,13 @@ void
O3ThreadContext<Impl>::halt(int delay)
{
DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
- getThreadNum());
+ threadId());
if (thread->status() == ThreadContext::Halted)
return;
thread->setStatus(ThreadContext::Halted);
- cpu->haltContext(thread->readTid());
+ cpu->haltContext(thread->threadId());
}
template <class Impl>
@@ -264,7 +245,7 @@ O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc)
{
// This function will mess things up unless the ROB is empty and
// there are no instructions in the pipeline.
- unsigned tid = thread->readTid();
+ unsigned tid = thread->threadId();
PhysRegIndex renamed_reg;
// First loop through the integer registers.
@@ -311,7 +292,7 @@ uint64_t
O3ThreadContext<Impl>::readIntReg(int reg_idx)
{
reg_idx = TheISA::flattenIntIndex(this, reg_idx);
- return cpu->readArchIntReg(reg_idx, thread->readTid());
+ return cpu->readArchIntReg(reg_idx, thread->threadId());
}
template <class Impl>
@@ -321,9 +302,9 @@ O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width)
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
switch(width) {
case 32:
- return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegSingle(reg_idx, thread->threadId());
case 64:
- return cpu->readArchFloatRegDouble(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegDouble(reg_idx, thread->threadId());
default:
panic("Unsupported width!");
return 0;
@@ -335,7 +316,7 @@ TheISA::FloatReg
O3ThreadContext<Impl>::readFloatReg(int reg_idx)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegSingle(reg_idx, thread->threadId());
}
template <class Impl>
@@ -344,7 +325,7 @@ O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width)
{
DPRINTF(Fault, "Reading floatint register through the TC!\n");
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegInt(reg_idx, thread->threadId());
}
template <class Impl>
@@ -352,7 +333,7 @@ TheISA::FloatRegBits
O3ThreadContext<Impl>::readFloatRegBits(int reg_idx)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegInt(reg_idx, thread->threadId());
}
template <class Impl>
@@ -360,11 +341,11 @@ void
O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
{
reg_idx = TheISA::flattenIntIndex(this, reg_idx);
- cpu->setArchIntReg(reg_idx, val, thread->readTid());
+ cpu->setArchIntReg(reg_idx, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -375,16 +356,16 @@ O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width)
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
switch(width) {
case 32:
- cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId());
break;
case 64:
- cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegDouble(reg_idx, val, thread->threadId());
break;
}
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -393,10 +374,10 @@ void
O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId());
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -407,11 +388,11 @@ O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val,
{
DPRINTF(Fault, "Setting floatint register through the TC!\n");
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegInt(reg_idx, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -420,11 +401,11 @@ void
O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegInt(reg_idx, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -432,11 +413,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setPC(uint64_t val)
{
- cpu->setPC(val, thread->readTid());
+ cpu->setPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -444,11 +425,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setNextPC(uint64_t val)
{
- cpu->setNextPC(val, thread->readTid());
+ cpu->setNextPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -456,11 +437,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setMicroPC(uint64_t val)
{
- cpu->setMicroPC(val, thread->readTid());
+ cpu->setMicroPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -468,11 +449,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setNextMicroPC(uint64_t val)
{
- cpu->setNextMicroPC(val, thread->readTid());
+ cpu->setNextMicroPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -480,11 +461,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
- cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid());
+ cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -493,36 +474,11 @@ void
O3ThreadContext<Impl>::setMiscReg(int misc_reg,
const MiscReg &val)
{
- cpu->setMiscReg(misc_reg, val, thread->readTid());
+ cpu->setMiscReg(misc_reg, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
-#if !FULL_SYSTEM
-
-template <class Impl>
-TheISA::IntReg
-O3ThreadContext<Impl>::getSyscallArg(int i)
-{
- return cpu->getSyscallArg(i, thread->readTid());
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setSyscallArg(int i, IntReg val)
-{
- cpu->setSyscallArg(i, val, thread->readTid());
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setSyscallReturn(SyscallReturn return_value)
-{
- cpu->setSyscallReturn(return_value, thread->readTid());
-}
-
-#endif // FULL_SYSTEM
-
diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh
index d8720b3ab..1f0e7a3bb 100644
--- a/src/cpu/o3/thread_state.hh
+++ b/src/cpu/o3/thread_state.hh
@@ -77,11 +77,11 @@ struct O3ThreadState : public ThreadState {
#if FULL_SYSTEM
O3ThreadState(O3CPU *_cpu, int _thread_num)
- : ThreadState(_cpu, -1, _thread_num),
+ : ThreadState(_cpu, _thread_num),
cpu(_cpu), inSyscall(0), trapPending(0)
{
- if (cpu->params->profile) {
- profile = new FunctionProfile(cpu->params->system->kernelSymtab);
+ if (cpu->params()->profile) {
+ profile = new FunctionProfile(cpu->params()->system->kernelSymtab);
Callback *cb =
new MakeCallback<O3ThreadState,
&O3ThreadState::dumpFuncProfile>(this);
@@ -96,7 +96,7 @@ struct O3ThreadState : public ThreadState {
}
#else
O3ThreadState(O3CPU *_cpu, int _thread_num, Process *_process, int _asid)
- : ThreadState(_cpu, -1, _thread_num, _process, _asid),
+ : ThreadState(_cpu, _thread_num, _process, _asid),
cpu(_cpu), inSyscall(0), trapPending(0)
{ }
#endif
diff --git a/src/cpu/ozone/OzoneCPU.py b/src/cpu/ozone/OzoneCPU.py
index b9cfb448f..37386898d 100644
--- a/src/cpu/ozone/OzoneCPU.py
+++ b/src/cpu/ozone/OzoneCPU.py
@@ -40,8 +40,6 @@ class DerivOzoneCPU(BaseCPU):
if build_env['USE_CHECKER']:
checker = Param.BaseCPU("Checker CPU")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
diff --git a/src/cpu/ozone/OzoneChecker.py b/src/cpu/ozone/OzoneChecker.py
index f20b8770e..bfa39ead9 100644
--- a/src/cpu/ozone/OzoneChecker.py
+++ b/src/cpu/ozone/OzoneChecker.py
@@ -39,5 +39,3 @@ class OzoneChecker(BaseCPU):
"If a load result is incorrect, only print a warning and do not exit")
function_trace = Param.Bool(False, "Enable function trace")
function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh
index 4cdc86c3c..ca858ce2e 100644
--- a/src/cpu/ozone/back_end.hh
+++ b/src/cpu/ozone/back_end.hh
@@ -157,13 +157,13 @@ class BackEnd
int numInsts;
int width;
- Stats::VectorDistribution<> occ_dist;
+ Stats::VectorDistribution occ_dist;
- Stats::Vector<> inst_count;
- Stats::Vector<> peak_inst_count;
- Stats::Scalar<> empty_count;
- Stats::Scalar<> current_count;
- Stats::Scalar<> fullCount;
+ Stats::Vector inst_count;
+ Stats::Vector peak_inst_count;
+ Stats::Scalar empty_count;
+ Stats::Scalar current_count;
+ Stats::Scalar fullCount;
Stats::Formula occ_rate;
Stats::Formula avg_residency;
@@ -371,45 +371,45 @@ class BackEnd
bool fetchRedirect[Impl::MaxThreads];
// number of cycles stalled for D-cache misses
-/* Stats::Scalar<> dcacheStallCycles;
+/* Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
*/
- Stats::Vector<> rob_cap_events;
- Stats::Vector<> rob_cap_inst_count;
- Stats::Vector<> iq_cap_events;
- Stats::Vector<> iq_cap_inst_count;
+ Stats::Vector rob_cap_events;
+ Stats::Vector rob_cap_inst_count;
+ Stats::Vector iq_cap_events;
+ Stats::Vector iq_cap_inst_count;
// total number of instructions executed
- Stats::Vector<> exe_inst;
- Stats::Vector<> exe_swp;
- Stats::Vector<> exe_nop;
- Stats::Vector<> exe_refs;
- Stats::Vector<> exe_loads;
- Stats::Vector<> exe_branches;
+ Stats::Vector exe_inst;
+ Stats::Vector exe_swp;
+ Stats::Vector exe_nop;
+ Stats::Vector exe_refs;
+ Stats::Vector exe_loads;
+ Stats::Vector exe_branches;
- Stats::Vector<> issued_ops;
+ Stats::Vector issued_ops;
// total number of loads forwaded from LSQ stores
- Stats::Vector<> lsq_forw_loads;
+ Stats::Vector lsq_forw_loads;
// total number of loads ignored due to invalid addresses
- Stats::Vector<> inv_addr_loads;
+ Stats::Vector inv_addr_loads;
// total number of software prefetches ignored due to invalid addresses
- Stats::Vector<> inv_addr_swpfs;
+ Stats::Vector inv_addr_swpfs;
// ready loads blocked due to memory disambiguation
- Stats::Vector<> lsq_blocked_loads;
+ Stats::Vector lsq_blocked_loads;
- Stats::Scalar<> lsqInversion;
+ Stats::Scalar lsqInversion;
- Stats::Vector<> n_issued_dist;
- Stats::VectorDistribution<> issue_delay_dist;
+ Stats::Vector n_issued_dist;
+ Stats::VectorDistribution issue_delay_dist;
- Stats::VectorDistribution<> queue_res_dist;
+ Stats::VectorDistribution queue_res_dist;
/*
- Stats::Vector<> stat_fu_busy;
- Stats::Vector2d<> stat_fuBusy;
- Stats::Vector<> dist_unissued;
- Stats::Vector2d<> stat_issued_inst_type;
+ Stats::Vector stat_fu_busy;
+ Stats::Vector2d stat_fuBusy;
+ Stats::Vector dist_unissued;
+ Stats::Vector2d stat_issued_inst_type;
Stats::Formula misspec_cnt;
Stats::Formula misspec_ipc;
@@ -422,34 +422,34 @@ class BackEnd
Stats::Formula commit_ipb;
Stats::Formula lsq_inv_rate;
*/
- Stats::Vector<> writeback_count;
- Stats::Vector<> producer_inst;
- Stats::Vector<> consumer_inst;
- Stats::Vector<> wb_penalized;
+ Stats::Vector writeback_count;
+ Stats::Vector producer_inst;
+ Stats::Vector consumer_inst;
+ Stats::Vector wb_penalized;
Stats::Formula wb_rate;
Stats::Formula wb_fanout;
Stats::Formula wb_penalized_rate;
// total number of instructions committed
- Stats::Vector<> stat_com_inst;
- Stats::Vector<> stat_com_swp;
- Stats::Vector<> stat_com_refs;
- Stats::Vector<> stat_com_loads;
- Stats::Vector<> stat_com_membars;
- Stats::Vector<> stat_com_branches;
+ Stats::Vector stat_com_inst;
+ Stats::Vector stat_com_swp;
+ Stats::Vector stat_com_refs;
+ Stats::Vector stat_com_loads;
+ Stats::Vector stat_com_membars;
+ Stats::Vector stat_com_branches;
- Stats::Distribution<> n_committed_dist;
+ Stats::Distribution n_committed_dist;
- Stats::Scalar<> commit_eligible_samples;
- Stats::Vector<> commit_eligible;
+ Stats::Scalar commit_eligible_samples;
+ Stats::Vector commit_eligible;
- Stats::Scalar<> ROB_fcount;
+ Stats::Scalar ROB_fcount;
Stats::Formula ROB_full_rate;
- Stats::Vector<> ROB_count; // cumulative ROB occupancy
+ Stats::Vector ROB_count; // cumulative ROB occupancy
Stats::Formula ROB_occ_rate;
- Stats::VectorDistribution<> ROB_occ_dist;
+ Stats::VectorDistribution ROB_occ_dist;
public:
void dumpInsts();
};
@@ -482,8 +482,8 @@ BackEnd<Impl>::read(RequestPtr req, T &data, int load_idx)
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
-// status = DcacheMissStall;
+// unscheduleTickEvent();
+// status = DcacheMissStall;
DPRINTF(OzoneCPU, "Dcache miss stall!\n");
} else {
// do functional access
@@ -524,8 +524,8 @@ BackEnd<Impl>::write(RequestPtr req, T &data, int store_idx)
if (result != MA_HIT && dcacheInterface->doEvents()) {
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
-// status = DcacheMissStall;
+// unscheduleTickEvent();
+// status = DcacheMissStall;
DPRINTF(OzoneCPU, "Dcache miss stall!\n");
}
}
diff --git a/src/cpu/ozone/base_dyn_inst.cc b/src/cpu/ozone/base_dyn_inst.cc
index 5a3a69dff..e0570fd16 100644
--- a/src/cpu/ozone/base_dyn_inst.cc
+++ b/src/cpu/ozone/base_dyn_inst.cc
@@ -33,7 +33,3 @@
// Explicit instantiation
template class BaseDynInst<OzoneImpl>;
-
-template <>
-int
-BaseDynInst<OzoneImpl>::instcount = 0;
diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh
index b0ea2cba9..0bfb4bfa9 100644
--- a/src/cpu/ozone/cpu.hh
+++ b/src/cpu/ozone/cpu.hh
@@ -116,10 +116,6 @@ class OzoneCPU : public BaseCPU
BaseCPU *getCpuPtr();
- void setCpuId(int id);
-
- int readCpuId() { return thread->readCpuId(); }
-
TheISA::ITB *getITBPtr() { return cpu->itb; }
TheISA::DTB * getDTBPtr() { return cpu->dtb; }
@@ -134,10 +130,8 @@ class OzoneCPU : public BaseCPU
FunctionalPort *getPhysPort() { return thread->getPhysPort(); }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL)
- { return thread->getVirtPort(tc); }
-
- void delVirtPort(VirtualPort *vp);
+ VirtualPort *getVirtPort()
+ { return thread->getVirtPort(); }
#else
TranslatingPort *getMemPort() { return thread->getMemPort(); }
@@ -182,7 +176,7 @@ class OzoneCPU : public BaseCPU
void profileSample();
#endif
- int getThreadNum();
+ int threadId();
// Also somewhat obnoxious. Really only used for the TLB fault.
TheISA::MachInst getInst();
@@ -252,30 +246,11 @@ class OzoneCPU : public BaseCPU
bool misspeculating() { return false; }
#if !FULL_SYSTEM
- TheISA::IntReg getSyscallArg(int i)
- {
- assert(i < TheISA::NumArgumentRegs);
- return thread->renameTable[TheISA::ArgumentReg[i]]->readIntResult();
- }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, TheISA::IntReg val)
- {
- assert(i < TheISA::NumArgumentRegs);
- thread->renameTable[TheISA::ArgumentReg[i]]->setIntResult(i);
- }
-
- void setSyscallReturn(SyscallReturn return_value)
- { cpu->setSyscallReturn(return_value, thread->readTid()); }
-
Counter readFuncExeInst() { return thread->funcExeInst; }
void setFuncExeInst(Counter new_val)
{ thread->funcExeInst = new_val; }
#endif
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- { panic("Not supported on Alpha!"); }
};
// Ozone specific thread context
@@ -296,6 +271,11 @@ class OzoneCPU : public BaseCPU
// main simulation loop (one cycle)
void tick();
+#ifndef NDEBUG
+ /** Count of total number of dynamic instructions in flight. */
+ int instcount;
+#endif
+
std::set<InstSeqNum> snList;
std::set<Addr> lockAddrList;
private:
@@ -337,7 +317,7 @@ class OzoneCPU : public BaseCPU
Status _status;
public:
- void post_interrupt(int int_num, int index);
+ void wakeup();
void zero_fill_64(Addr addr) {
static int warned = 0;
@@ -358,12 +338,6 @@ class OzoneCPU : public BaseCPU
public:
BaseCPU *getCpuPtr() { return this; }
- void setCpuId(int id) { cpuId = id; }
-
- int readCpuId() { return cpuId; }
-
- int cpuId;
-
void switchOut();
void signalSwitched();
void takeOverFrom(BaseCPU *oldCPU);
@@ -416,7 +390,7 @@ class OzoneCPU : public BaseCPU
Counter startNumLoad;
// number of idle cycles
- Stats::Average<> notIdleFraction;
+ Stats::Average notIdleFraction;
Stats::Formula idleFraction;
public:
@@ -425,59 +399,20 @@ class OzoneCPU : public BaseCPU
void demapPage(Addr vaddr, uint64_t asn)
{
- itb->demap(vaddr, asn);
- dtb->demap(vaddr, asn);
+ cpu->itb->demap(vaddr, asn);
+ cpu->dtb->demap(vaddr, asn);
}
void demapInstPage(Addr vaddr, uint64_t asn)
{
- itb->demap(vaddr, asn);
+ cpu->itb->demap(vaddr, asn);
}
void demapDataPage(Addr vaddr, uint64_t asn)
{
- dtb->demap(vaddr, asn);
- }
-
-#if FULL_SYSTEM
- /** Translates instruction requestion. */
- Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return itb->translate(req, thread->getTC());
- }
-
- /** Translates data read request. */
- Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return dtb->translate(req, thread->getTC(), false);
- }
-
- /** Translates data write request. */
- Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return dtb->translate(req, thread->getTC(), true);
- }
-
-#else
- /** Translates instruction requestion in syscall emulation mode. */
- Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return thread->getProcessPtr()->pTable->translate(req);
- }
-
- /** Translates data read request in syscall emulation mode. */
- Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return thread->getProcessPtr()->pTable->translate(req);
+ cpu->dtb->demap(vaddr, asn);
}
- /** Translates data write request in syscall emulation mode. */
- Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return thread->getProcessPtr()->pTable->translate(req);
- }
-#endif
-
/** CPU read function, forwards read to LSQ. */
template <class T>
Fault read(Request *req, T &data, int load_idx)
@@ -517,7 +452,6 @@ class OzoneCPU : public BaseCPU
void processInterrupts();
#else
void syscall(uint64_t &callnum);
- void setSyscallReturn(SyscallReturn return_value, int tid);
#endif
ThreadContext *tcBase() { return tc; }
@@ -539,7 +473,7 @@ class OzoneCPU : public BaseCPU
bool lockFlag;
- Stats::Scalar<> quiesceCycles;
+ Stats::Scalar quiesceCycles;
Checker<DynInstPtr> *checker;
};
diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh
index 0c7105382..aa76c8aa6 100644
--- a/src/cpu/ozone/cpu_impl.hh
+++ b/src/cpu/ozone/cpu_impl.hh
@@ -95,6 +95,9 @@ OzoneCPU<Impl>::OzoneCPU(Params *p)
: BaseCPU(p), thread(this, 0, p->workload[0], 0),
tickEvent(this, p->width),
#endif
+#ifndef NDEBUG
+ instcount(0),
+#endif
comm(5, 5)
{
frontEnd = new FrontEnd(p);
@@ -417,7 +420,7 @@ OzoneCPU<Impl>::init()
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, tc->readCpuId());
+ TheISA::initCPU(tc, tc->contextId());
}
#endif
frontEnd->renameTable.copyFrom(thread.renameTable);
@@ -579,16 +582,14 @@ OzoneCPU<Impl>::dbg_vtophys(Addr addr)
#if FULL_SYSTEM
template <class Impl>
void
-OzoneCPU<Impl>::post_interrupt(int int_num, int index)
+OzoneCPU<Impl>::wakeup()
{
- BaseCPU::post_interrupt(int_num, index);
-
if (_status == Idle) {
DPRINTF(IPI,"Suspended Processor awoke\n");
-// thread.activate();
+// thread.activate();
// Hack for now. Otherwise might have to go through the tc, or
// I need to figure out what's the right thing to call.
- activateContext(thread.readTid(), 1);
+ activateContext(thread.threadId(), 1);
}
}
#endif // FULL_SYSTEM
@@ -647,26 +648,6 @@ OzoneCPU<Impl>::syscall(uint64_t &callnum)
frontEnd->renameTable.copyFrom(thread.renameTable);
backEnd->renameTable.copyFrom(thread.renameTable);
}
-
-template <class Impl>
-void
-OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- // check for error condition. Alpha syscall convention is to
- // indicate success/failure in reg a3 (r19) and put the
- // return value itself in the standard return value reg (v0).
- if (return_value.successful()) {
- // no error
- thread.renameTable[SyscallSuccessReg]->setIntResult(0);
- thread.renameTable[ReturnValueReg]->setIntResult(
- return_value.value());
- } else {
- // got an error, return details
- thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1);
- thread.renameTable[ReturnValueReg]->setIntResult(
- -return_value.value());
- }
-}
#else
template <class Impl>
Fault
@@ -693,10 +674,10 @@ OzoneCPU<Impl>::processInterrupts()
// Check if there are any outstanding interrupts
//Handle the interrupts
- Fault interrupt = this->interrupts.getInterrupt(thread.getTC());
+ Fault interrupt = this->interrupts->getInterrupt(thread.getTC());
if (interrupt != NoFault) {
- this->interrupts.updateIntrInfo(thread.getTC());
+ this->interrupts->updateIntrInfo(thread.getTC());
interrupt->invoke(thread.getTC());
}
}
@@ -711,7 +692,7 @@ OzoneCPU<Impl>::simPalCheck(int palFunc)
switch (palFunc) {
case PAL::halt:
- haltContext(thread.readTid());
+ haltContext(thread.threadId());
if (--System::numSystemsRunning == 0)
exitSimLoop("all cpus halted");
break;
@@ -736,24 +717,6 @@ OzoneCPU<Impl>::OzoneTC::getCpuPtr()
template <class Impl>
void
-OzoneCPU<Impl>::OzoneTC::setCpuId(int id)
-{
- cpu->cpuId = id;
- thread->setCpuId(id);
-}
-
-#if FULL_SYSTEM
-template <class Impl>
-void
-OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp)
-{
- vp->removeConn();
- delete vp;
-}
-#endif
-
-template <class Impl>
-void
OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status)
{
thread->setStatus(new_status);
@@ -763,7 +726,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::activate(int delay)
{
- cpu->activateContext(thread->readTid(), delay);
+ cpu->activateContext(thread->threadId(), delay);
}
/// Set the status to Suspended.
@@ -771,7 +734,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::suspend()
{
- cpu->suspendContext(thread->readTid());
+ cpu->suspendContext(thread->threadId());
}
/// Set the status to Unallocated.
@@ -779,7 +742,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::deallocate(int delay)
{
- cpu->deallocateContext(thread->readTid(), delay);
+ cpu->deallocateContext(thread->threadId(), delay);
}
/// Set the status to Halted.
@@ -787,7 +750,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::halt()
{
- cpu->haltContext(thread->readTid());
+ cpu->haltContext(thread->threadId());
}
#if FULL_SYSTEM
@@ -813,7 +776,8 @@ OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context)
// copy over functional state
setStatus(old_context->status());
copyArchRegs(old_context);
- setCpuId(old_context->readCpuId());
+ setCpuId(old_context->cpuId());
+ setContextId(old_context->contextId());
thread->setInst(old_context->getInst());
#if !FULL_SYSTEM
@@ -901,9 +865,9 @@ OzoneCPU<Impl>::OzoneTC::profileSample()
template <class Impl>
int
-OzoneCPU<Impl>::OzoneTC::getThreadNum()
+OzoneCPU<Impl>::OzoneTC::threadId()
{
- return thread->readTid();
+ return thread->threadId();
}
template <class Impl>
diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh
index 667392c06..38fc89e3f 100644
--- a/src/cpu/ozone/front_end.hh
+++ b/src/cpu/ozone/front_end.hh
@@ -275,48 +275,48 @@ class FrontEnd
private:
// number of idle cycles
/*
- Stats::Average<> notIdleFraction;
+ Stats::Average notIdleFraction;
Stats::Formula idleFraction;
*/
// @todo: Consider making these vectors and tracking on a per thread basis.
/** Stat for total number of cycles stalled due to an icache miss. */
- Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar icacheStallCycles;
/** Stat for total number of fetched instructions. */
- Stats::Scalar<> fetchedInsts;
- Stats::Scalar<> fetchedBranches;
+ Stats::Scalar fetchedInsts;
+ Stats::Scalar fetchedBranches;
/** Stat for total number of predicted branches. */
- Stats::Scalar<> predictedBranches;
+ Stats::Scalar predictedBranches;
/** Stat for total number of cycles spent fetching. */
- Stats::Scalar<> fetchCycles;
+ Stats::Scalar fetchCycles;
- Stats::Scalar<> fetchIdleCycles;
+ Stats::Scalar fetchIdleCycles;
/** Stat for total number of cycles spent squashing. */
- Stats::Scalar<> fetchSquashCycles;
+ Stats::Scalar fetchSquashCycles;
/** Stat for total number of cycles spent blocked due to other stages in
* the pipeline.
*/
- Stats::Scalar<> fetchBlockedCycles;
+ Stats::Scalar fetchBlockedCycles;
/** Stat for total number of fetched cache lines. */
- Stats::Scalar<> fetchedCacheLines;
+ Stats::Scalar fetchedCacheLines;
- Stats::Scalar<> fetchIcacheSquashes;
+ Stats::Scalar fetchIcacheSquashes;
/** Distribution of number of instructions fetched each cycle. */
- Stats::Distribution<> fetchNisnDist;
-// Stats::Vector<> qfull_iq_occupancy;
-// Stats::VectorDistribution<> qfull_iq_occ_dist_;
+ Stats::Distribution fetchNisnDist;
+// Stats::Vector qfull_iq_occupancy;
+// Stats::VectorDistribution qfull_iq_occ_dist_;
Stats::Formula idleRate;
Stats::Formula branchRate;
Stats::Formula fetchRate;
- Stats::Scalar<> IFQCount; // cumulative IFQ occupancy
+ Stats::Scalar IFQCount; // cumulative IFQ occupancy
Stats::Formula IFQOccupancy;
Stats::Formula IFQLatency;
- Stats::Scalar<> IFQFcount; // cumulative IFQ full count
+ Stats::Scalar IFQFcount; // cumulative IFQ full count
Stats::Formula IFQFullRate;
- Stats::Scalar<> dispatchCountStat;
- Stats::Scalar<> dispatchedSerializing;
- Stats::Scalar<> dispatchedTempSerializing;
- Stats::Scalar<> dispatchSerializeStallCycles;
+ Stats::Scalar dispatchCountStat;
+ Stats::Scalar dispatchedSerializing;
+ Stats::Scalar dispatchedTempSerializing;
+ Stats::Scalar dispatchSerializeStallCycles;
Stats::Formula dispatchRate;
Stats::Formula regIntFull;
Stats::Formula regFpFull;
diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh
index 198ce0308..6b47ef539 100644
--- a/src/cpu/ozone/front_end_impl.hh
+++ b/src/cpu/ozone/front_end_impl.hh
@@ -477,10 +477,10 @@ FrontEnd<Impl>::fetchCacheLine()
// Setup the memReq to do a read of the first isntruction's address.
// Set the appropriate read size and flags as well.
memReq = new Request(0, fetch_PC, cacheBlkSize, 0,
- PC, cpu->readCpuId(), 0);
+ PC, cpu->thread->contextId());
// Translate the instruction request.
- fault = cpu->translateInstReq(memReq, thread);
+ fault = cpu->itb->translateAtomic(memReq, thread);
// Now do the timing access to see whether or not the instruction
// exists within the cache.
diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh
index aef29b1e2..e930144be 100644
--- a/src/cpu/ozone/inorder_back_end.hh
+++ b/src/cpu/ozone/inorder_back_end.hh
@@ -192,7 +192,7 @@ class InorderBackEnd
TimeBuffer<CommStruct> *comm;
// number of cycles stalled for D-cache misses
- Stats::Scalar<> dcacheStallCycles;
+ Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
};
@@ -204,7 +204,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags)
memReq->reset(addr, sizeof(T), flags);
// translate to physical address
- Fault fault = cpu->translateDataReadReq(memReq);
+ Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), false);
// if we have a cache, do cache access too
if (fault == NoFault && dcacheInterface) {
@@ -222,7 +222,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags)
// are executed twice.
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissLoadStall;
DPRINTF(IBE, "Dcache miss stall!\n");
} else {
@@ -245,11 +245,11 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
memReq->reset(addr, sizeof(T), flags);
// translate to physical address
- Fault fault = cpu->translateDataWriteReq(memReq);
+ Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), true);
if (fault == NoFault && dcacheInterface) {
memReq->cmd = Write;
-// memcpy(memReq->data,(uint8_t *)&data,memReq->size);
+// memcpy(memReq->data,(uint8_t *)&data,memReq->size);
memReq->completionEvent = NULL;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
@@ -261,7 +261,7 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
if (result != MA_HIT) {
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissStoreStall;
DPRINTF(IBE, "Dcache miss stall!\n");
} else {
@@ -307,7 +307,7 @@ InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx)
if (result != MA_HIT) {
req->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissLoadStall;
DPRINTF(IBE, "Dcache miss load stall!\n");
} else {
@@ -372,7 +372,7 @@ InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx)
if (result != MA_HIT) {
req->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissStoreStall;
DPRINTF(IBE, "Dcache miss store stall!\n");
} else {
diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh
index cf8634a42..798b628d6 100644
--- a/src/cpu/ozone/inorder_back_end_impl.hh
+++ b/src/cpu/ozone/inorder_back_end_impl.hh
@@ -149,8 +149,7 @@ InorderBackEnd<Impl>::tick()
// if (interrupt) then set thread PC, stall front end, record that
// I'm waiting for it to drain. (for now just squash)
#if FULL_SYSTEM
- if (interruptBlocked ||
- cpu->check_interrupts(tc)) {
+ if (interruptBlocked || cpu->checkInterrupts(tc)) {
if (!robEmpty()) {
interruptBlocked = true;
//AlphaDep
diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh
index a11d5204b..e840d5c21 100644
--- a/src/cpu/ozone/inst_queue.hh
+++ b/src/cpu/ozone/inst_queue.hh
@@ -473,35 +473,35 @@ class InstQueue
void dumpInsts();
/** Stat for number of instructions added. */
- Stats::Scalar<> iqInstsAdded;
+ Stats::Scalar iqInstsAdded;
/** Stat for number of non-speculative instructions added. */
- Stats::Scalar<> iqNonSpecInstsAdded;
-// Stats::Scalar<> iqIntInstsAdded;
+ Stats::Scalar iqNonSpecInstsAdded;
+// Stats::Scalar iqIntInstsAdded;
/** Stat for number of integer instructions issued. */
- Stats::Scalar<> iqIntInstsIssued;
-// Stats::Scalar<> iqFloatInstsAdded;
+ Stats::Scalar iqIntInstsIssued;
+// Stats::Scalar iqFloatInstsAdded;
/** Stat for number of floating point instructions issued. */
- Stats::Scalar<> iqFloatInstsIssued;
-// Stats::Scalar<> iqBranchInstsAdded;
+ Stats::Scalar iqFloatInstsIssued;
+// Stats::Scalar iqBranchInstsAdded;
/** Stat for number of branch instructions issued. */
- Stats::Scalar<> iqBranchInstsIssued;
-// Stats::Scalar<> iqMemInstsAdded;
+ Stats::Scalar iqBranchInstsIssued;
+// Stats::Scalar iqMemInstsAdded;
/** Stat for number of memory instructions issued. */
- Stats::Scalar<> iqMemInstsIssued;
-// Stats::Scalar<> iqMiscInstsAdded;
+ Stats::Scalar iqMemInstsIssued;
+// Stats::Scalar iqMiscInstsAdded;
/** Stat for number of miscellaneous instructions issued. */
- Stats::Scalar<> iqMiscInstsIssued;
+ Stats::Scalar iqMiscInstsIssued;
/** Stat for number of squashed instructions that were ready to issue. */
- Stats::Scalar<> iqSquashedInstsIssued;
+ Stats::Scalar iqSquashedInstsIssued;
/** Stat for number of squashed instructions examined when squashing. */
- Stats::Scalar<> iqSquashedInstsExamined;
+ Stats::Scalar iqSquashedInstsExamined;
/** Stat for number of squashed instruction operands examined when
* squashing.
*/
- Stats::Scalar<> iqSquashedOperandsExamined;
+ Stats::Scalar iqSquashedOperandsExamined;
/** Stat for number of non-speculative instructions removed due to a squash.
*/
- Stats::Scalar<> iqSquashedNonSpecRemoved;
+ Stats::Scalar iqSquashedNonSpecRemoved;
};
diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh
index 981682c26..47be245e5 100644
--- a/src/cpu/ozone/lsq_unit.hh
+++ b/src/cpu/ozone/lsq_unit.hh
@@ -331,7 +331,7 @@ class OzoneLSQ {
//list<InstSeqNum> mshrSeqNums;
- //Stats::Scalar<> dcacheStallCycles;
+ //Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
/** Wire to read information from the issue stage time queue. */
diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh
index 84a90eede..c24410520 100644
--- a/src/cpu/ozone/lsq_unit_impl.hh
+++ b/src/cpu/ozone/lsq_unit_impl.hh
@@ -553,7 +553,7 @@ OzoneLSQ<Impl>::writebackStores()
MemReqPtr req = storeQueue[storeWBIdx].req;
storeQueue[storeWBIdx].committed = true;
-// Fault fault = cpu->translateDataReadReq(req);
+// Fault fault = cpu->translateDataReadReq(req);
req->cmd = Write;
req->completionEvent = NULL;
req->time = curTick;
diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh
index a335ab7dc..4a1657c9b 100644
--- a/src/cpu/ozone/lw_back_end.hh
+++ b/src/cpu/ozone/lw_back_end.hh
@@ -326,47 +326,47 @@ class LWBackEnd
bool exactFullStall;
// number of cycles stalled for D-cache misses
-/* Stats::Scalar<> dcacheStallCycles;
+/* Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
*/
- Stats::Vector<> robCapEvents;
- Stats::Vector<> robCapInstCount;
- Stats::Vector<> iqCapEvents;
- Stats::Vector<> iqCapInstCount;
+ Stats::Vector robCapEvents;
+ Stats::Vector robCapInstCount;
+ Stats::Vector iqCapEvents;
+ Stats::Vector iqCapInstCount;
// total number of instructions executed
- Stats::Vector<> exeInst;
- Stats::Vector<> exeSwp;
- Stats::Vector<> exeNop;
- Stats::Vector<> exeRefs;
- Stats::Vector<> exeLoads;
- Stats::Vector<> exeBranches;
+ Stats::Vector exeInst;
+ Stats::Vector exeSwp;
+ Stats::Vector exeNop;
+ Stats::Vector exeRefs;
+ Stats::Vector exeLoads;
+ Stats::Vector exeBranches;
- Stats::Vector<> issuedOps;
+ Stats::Vector issuedOps;
// total number of loads forwaded from LSQ stores
- Stats::Vector<> lsqForwLoads;
+ Stats::Vector lsqForwLoads;
// total number of loads ignored due to invalid addresses
- Stats::Vector<> invAddrLoads;
+ Stats::Vector invAddrLoads;
// total number of software prefetches ignored due to invalid addresses
- Stats::Vector<> invAddrSwpfs;
+ Stats::Vector invAddrSwpfs;
// ready loads blocked due to memory disambiguation
- Stats::Vector<> lsqBlockedLoads;
+ Stats::Vector lsqBlockedLoads;
- Stats::Scalar<> lsqInversion;
+ Stats::Scalar lsqInversion;
- Stats::Vector<> nIssuedDist;
+ Stats::Vector nIssuedDist;
/*
- Stats::VectorDistribution<> issueDelayDist;
+ Stats::VectorDistribution issueDelayDist;
- Stats::VectorDistribution<> queueResDist;
+ Stats::VectorDistribution queueResDist;
*/
/*
- Stats::Vector<> stat_fu_busy;
- Stats::Vector2d<> stat_fuBusy;
- Stats::Vector<> dist_unissued;
- Stats::Vector2d<> stat_issued_inst_type;
+ Stats::Vector stat_fu_busy;
+ Stats::Vector2d stat_fuBusy;
+ Stats::Vector dist_unissued;
+ Stats::Vector2d stat_issued_inst_type;
Stats::Formula misspec_cnt;
Stats::Formula misspec_ipc;
@@ -379,37 +379,37 @@ class LWBackEnd
Stats::Formula commit_ipb;
Stats::Formula lsq_inv_rate;
*/
- Stats::Vector<> writebackCount;
- Stats::Vector<> producerInst;
- Stats::Vector<> consumerInst;
- Stats::Vector<> wbPenalized;
+ Stats::Vector writebackCount;
+ Stats::Vector producerInst;
+ Stats::Vector consumerInst;
+ Stats::Vector wbPenalized;
Stats::Formula wbRate;
Stats::Formula wbFanout;
Stats::Formula wbPenalizedRate;
// total number of instructions committed
- Stats::Vector<> statComInst;
- Stats::Vector<> statComSwp;
- Stats::Vector<> statComRefs;
- Stats::Vector<> statComLoads;
- Stats::Vector<> statComMembars;
- Stats::Vector<> statComBranches;
+ Stats::Vector statComInst;
+ Stats::Vector statComSwp;
+ Stats::Vector statComRefs;
+ Stats::Vector statComLoads;
+ Stats::Vector statComMembars;
+ Stats::Vector statComBranches;
- Stats::Distribution<> nCommittedDist;
+ Stats::Distribution nCommittedDist;
- Stats::Scalar<> commitEligibleSamples;
- Stats::Vector<> commitEligible;
+ Stats::Scalar commitEligibleSamples;
+ Stats::Vector commitEligible;
- Stats::Vector<> squashedInsts;
- Stats::Vector<> ROBSquashedInsts;
+ Stats::Vector squashedInsts;
+ Stats::Vector ROBSquashedInsts;
- Stats::Scalar<> ROBFcount;
+ Stats::Scalar ROBFcount;
Stats::Formula ROBFullRate;
- Stats::Vector<> ROBCount; // cumulative ROB occupancy
+ Stats::Vector ROBCount; // cumulative ROB occupancy
Stats::Formula ROBOccRate;
-// Stats::VectorDistribution<> ROBOccDist;
+// Stats::VectorDistribution ROBOccDist;
public:
void dumpInsts();
diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh
index a5d79a789..60c42edd3 100644
--- a/src/cpu/ozone/lw_back_end_impl.hh
+++ b/src/cpu/ozone/lw_back_end_impl.hh
@@ -525,10 +525,7 @@ template <class Impl>
void
LWBackEnd<Impl>::checkInterrupts()
{
- if (cpu->checkInterrupts &&
- cpu->check_interrupts(tc) &&
- !trapSquash &&
- !tcSquash) {
+ if (cpu->checkInterrupts(tc) && !trapSquash && !tcSquash) {
frontEnd->interruptPending = true;
if (robEmpty() && !LSQ.hasStoresToWB()) {
// Will need to squash all instructions currently in flight and have
diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh
index 7fc8b6307..4f8101bc0 100644
--- a/src/cpu/ozone/lw_lsq.hh
+++ b/src/cpu/ozone/lw_lsq.hh
@@ -39,6 +39,7 @@
#include "arch/faults.hh"
#include "arch/types.hh"
#include "config/full_system.hh"
+#include "base/fast_alloc.hh"
#include "base/hashmap.hh"
#include "cpu/inst_seq.hh"
#include "mem/packet.hh"
@@ -301,7 +302,7 @@ class OzoneLWLSQ {
};
/** Derived class to hold any sender state the LSQ needs. */
- class LSQSenderState : public Packet::SenderState
+ class LSQSenderState : public Packet::SenderState, public FastAlloc
{
public:
/** Default constructor. */
@@ -410,9 +411,9 @@ class OzoneLWLSQ {
//list<InstSeqNum> mshrSeqNums;
/** Tota number of memory ordering violations. */
- Stats::Scalar<> lsqMemOrderViolation;
+ Stats::Scalar lsqMemOrderViolation;
- //Stats::Scalar<> dcacheStallCycles;
+ //Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
// Make these per thread?
diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc
index 438218df2..79f5277d5 100644
--- a/src/cpu/pc_event.cc
+++ b/src/cpu/pc_event.cc
@@ -34,12 +34,12 @@
#include <string>
#include <utility>
+#include "base/debug.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "cpu/pc_event.hh"
-#include "sim/debug.hh"
#include "sim/core.hh"
#include "sim/system.hh"
diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc
index 81384d529..38ffb74e4 100644
--- a/src/cpu/quiesce_event.cc
+++ b/src/cpu/quiesce_event.cc
@@ -33,7 +33,7 @@
#include "cpu/quiesce_event.hh"
EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc)
- : Event(&mainEventQueue), tc(_tc)
+ : tc(_tc)
{
}
diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py
index 28c2aa9c9..b7174bb43 100644
--- a/src/cpu/simple/AtomicSimpleCPU.py
+++ b/src/cpu/simple/AtomicSimpleCPU.py
@@ -28,18 +28,15 @@
from m5.params import *
from m5 import build_env
-from BaseCPU import BaseCPU
+from BaseSimpleCPU import BaseSimpleCPU
-class AtomicSimpleCPU(BaseCPU):
+class AtomicSimpleCPU(BaseSimpleCPU):
type = 'AtomicSimpleCPU'
width = Param.Int(1, "CPU width")
- simulate_stalls = Param.Bool(False, "Simulate cache stall cycles")
- function_trace = Param.Bool(False, "Enable function trace")
- function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
+ simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles")
+ simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
physmem_port = Port("Physical Memory Port")
- _mem_ports = BaseCPU._mem_ports + \
+ _mem_ports = BaseSimpleCPU._mem_ports + \
['icache_port', 'dcache_port', 'physmem_port']
diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py
new file mode 100644
index 000000000..9f528bc20
--- /dev/null
+++ b/src/cpu/simple/BaseSimpleCPU.py
@@ -0,0 +1,34 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# 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: Gabe Black
+
+from m5.params import *
+from BaseCPU import BaseCPU
+
+class BaseSimpleCPU(BaseCPU):
+ type = 'BaseSimpleCPU'
+ abstract = True
diff --git a/src/cpu/simple/SConscript b/src/cpu/simple/SConscript
index c090a938c..76598666f 100644
--- a/src/cpu/simple/SConscript
+++ b/src/cpu/simple/SConscript
@@ -47,3 +47,4 @@ if 'AtomicSimpleCPU' in env['CPU_MODELS'] or \
if need_simple_base:
Source('base.cc')
+ SimObject('BaseSimpleCPU.py')
diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py
index 7e777e813..ce6839241 100644
--- a/src/cpu/simple/TimingSimpleCPU.py
+++ b/src/cpu/simple/TimingSimpleCPU.py
@@ -28,14 +28,10 @@
from m5.params import *
from m5 import build_env
-from BaseCPU import BaseCPU
+from BaseSimpleCPU import BaseSimpleCPU
-class TimingSimpleCPU(BaseCPU):
+class TimingSimpleCPU(BaseSimpleCPU):
type = 'TimingSimpleCPU'
- function_trace = Param.Bool(False, "Enable function trace")
- function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
- _mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port']
+ _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port']
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
index 23bd40b9b..17f93c882 100644
--- a/src/cpu/simple/atomic.cc
+++ b/src/cpu/simple/atomic.cc
@@ -43,7 +43,7 @@ using namespace std;
using namespace TheISA;
AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
- : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+ : Event(CPU_Tick_Pri), cpu(c)
{
}
@@ -79,13 +79,12 @@ void
AtomicSimpleCPU::init()
{
BaseCPU::init();
- cpuId = tc->readCpuId();
#if FULL_SYSTEM
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, cpuId);
+ TheISA::initCPU(tc, tc->contextId());
}
#endif
if (hasPhysMemPort) {
@@ -94,9 +93,10 @@ AtomicSimpleCPU::init()
physmemPort.getPeerAddressRanges(pmAddrList, snoop);
physMemAddr = *pmAddrList.begin();
}
- ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
- data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
- data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
+ // Atomic doesn't do MT right now, so contextId == threadId
+ ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
+ data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
+ data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
}
bool
@@ -148,13 +148,14 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port)
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
- cpu->tcBase()->connectMemPorts();
+ cpu->tcBase()->connectMemPorts(cpu->tcBase());
#endif
}
-AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
- : BaseSimpleCPU(p), tickEvent(this),
- width(p->width), simulate_stalls(p->simulate_stalls),
+AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
+ : BaseSimpleCPU(p), tickEvent(this), width(p->width),
+ simulate_data_stalls(p->simulate_data_stalls),
+ simulate_inst_stalls(p->simulate_inst_stalls),
icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
physmemPort(name() + "-iport", this), hasPhysMemPort(false)
{
@@ -175,8 +176,6 @@ AtomicSimpleCPU::serialize(ostream &os)
{
SimObject::State so_state = SimObject::getState();
SERIALIZE_ENUM(so_state);
- Status _status = status();
- SERIALIZE_ENUM(_status);
BaseSimpleCPU::serialize(os);
nameOut(os, csprintf("%s.tickEvent", name()));
tickEvent.serialize(os);
@@ -187,7 +186,6 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
SimObject::State so_state;
UNSERIALIZE_ENUM(so_state);
- UNSERIALIZE_ENUM(_status);
BaseSimpleCPU::unserialize(cp, section);
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
}
@@ -203,16 +201,15 @@ AtomicSimpleCPU::resume()
changeState(SimObject::Running);
if (thread->status() == ThreadContext::Active) {
- if (!tickEvent.scheduled()) {
- tickEvent.schedule(nextCycle());
- }
+ if (!tickEvent.scheduled())
+ schedule(tickEvent, nextCycle());
}
}
void
AtomicSimpleCPU::switchOut()
{
- assert(status() == Running || status() == Idle);
+ assert(_status == Running || _status == Idle);
_status = SwitchedOut;
tickEvent.squash();
@@ -232,7 +229,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
ThreadContext *tc = threadContexts[i];
if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
break;
}
}
@@ -240,10 +237,9 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
_status = Idle;
}
assert(threadContexts.size() == 1);
- cpuId = tc->readCpuId();
- ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
- data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
- data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
+ ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
+ data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
+ data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
}
@@ -262,7 +258,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay)
numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
//Make sure ticks are still on multiples of cycles
- tickEvent.schedule(nextCycle(curTick + ticks(delay)));
+ schedule(tickEvent, nextCycle(curTick + ticks(delay)));
_status = Running;
}
@@ -280,7 +276,7 @@ AtomicSimpleCPU::suspendContext(int thread_num)
// tick event may not be scheduled if this gets called from inside
// an instruction's execution, e.g. "quiesce"
if (tickEvent.scheduled())
- tickEvent.deschedule();
+ deschedule(tickEvent);
notIdleFraction--;
_status = Idle;
@@ -318,7 +314,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
req->setVirt(0, addr, dataSize, flags, thread->readPC());
// translate to physical address
- Fault fault = thread->translateDataReadReq(req);
+ Fault fault = thread->dtb->translateAtomic(req, tc, false);
// Now do the access.
if (fault == NoFault) {
@@ -355,6 +351,9 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
if (secondAddr <= addr)
{
data = gtoh(data);
+ if (traceData) {
+ traceData->setData(data);
+ }
return fault;
}
@@ -371,61 +370,6 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
}
}
-Fault
-AtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr,
- int size, unsigned flags)
-{
- // use the CPU's statically allocated read request and packet objects
- Request *req = &data_read_req;
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- //The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
- //The size of the data we're trying to read.
- int dataSize = size;
-
- bool firstTimeThrough = true;
-
- //The address of the second part of this access if it needs to be split
- //across a cache line boundary.
- Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize);
-
- if(secondAddr > vaddr)
- dataSize = secondAddr - vaddr;
-
- while(1) {
- req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
-
- // translate to physical address
- Fault fault = thread->translateDataReadReq(req);
-
- //If there's a fault, return it
- if (fault != NoFault)
- return fault;
-
- if (firstTimeThrough) {
- paddr = req->getPaddr();
- firstTimeThrough = false;
- }
-
- //If we don't need to access a second cache line, stop now.
- if (secondAddr <= vaddr)
- return fault;
-
- /*
- * Set up for accessing the second cache line.
- */
-
- //Adjust the size to get the remaining bytes.
- dataSize = vaddr + size - secondAddr;
- //And access the right address.
- vaddr = secondAddr;
- }
-}
-
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
@@ -508,7 +452,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
req->setVirt(0, addr, dataSize, flags, thread->readPC());
// translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
+ Fault fault = thread->dtb->translateAtomic(req, tc, true);
// Now do the access.
if (fault == NoFault) {
@@ -568,6 +512,9 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
// If the write needs to have a fault on the access, consider
// calling changeStatus() and changing it to "bad addr write"
// or something.
+ if (traceData) {
+ traceData->setData(gtoh(data));
+ }
return fault;
}
@@ -584,64 +531,6 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
}
}
-Fault
-AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- // use the CPU's statically allocated write request and packet objects
- Request *req = &data_write_req;
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- //The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
-
- //The address of the second part of this access if it needs to be split
- //across a cache line boundary.
- Addr secondAddr = roundDown(vaddr + size - 1, blockSize);
-
- //The size of the data we're trying to read.
- int dataSize = size;
-
- bool firstTimeThrough = true;
-
- if(secondAddr > vaddr)
- dataSize = secondAddr - vaddr;
-
- dcache_latency = 0;
-
- while(1) {
- req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
-
- // translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
-
- //If there's a fault or we don't need to access a second cache line,
- //stop now.
- if (fault != NoFault)
- return fault;
-
- if (firstTimeThrough) {
- paddr = req->getPaddr();
- firstTimeThrough = false;
- }
-
- if (secondAddr <= vaddr)
- return fault;
-
- /*
- * Set up for accessing the second cache line.
- */
-
- //Adjust the size to get the remaining bytes.
- dataSize = vaddr + size - secondAddr;
- //And access the right address.
- vaddr = secondAddr;
- }
-}
-
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -705,7 +594,7 @@ AtomicSimpleCPU::tick()
{
DPRINTF(SimpleCPU, "Tick\n");
- Tick latency = ticks(1); // instruction takes one cycle by default
+ Tick latency = 0;
for (int i = 0; i < width; ++i) {
numCycles++;
@@ -715,31 +604,43 @@ AtomicSimpleCPU::tick()
checkPcEventQueue();
- Fault fault = setupFetchRequest(&ifetch_req);
+ Fault fault = NoFault;
+
+ bool fromRom = isRomMicroPC(thread->readMicroPC());
+ if (!fromRom && !curMacroStaticInst) {
+ setupFetchRequest(&ifetch_req);
+ fault = thread->itb->translateAtomic(&ifetch_req, tc);
+ }
if (fault == NoFault) {
Tick icache_latency = 0;
bool icache_access = false;
dcache_access = false; // assume no dcache access
- //Fetch more instruction memory if necessary
- //if(predecoder.needMoreBytes())
- //{
- icache_access = true;
- Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
- Packet::Broadcast);
- ifetch_pkt.dataStatic(&inst);
-
- if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
- icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
- else
- icache_latency = icachePort.sendAtomic(&ifetch_pkt);
+ if (!fromRom && !curMacroStaticInst) {
+ // This is commented out because the predecoder would act like
+ // a tiny cache otherwise. It wouldn't be flushed when needed
+ // like the I cache. It should be flushed, and when that works
+ // this code should be uncommented.
+ //Fetch more instruction memory if necessary
+ //if(predecoder.needMoreBytes())
+ //{
+ icache_access = true;
+ Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
+ Packet::Broadcast);
+ ifetch_pkt.dataStatic(&inst);
+
+ if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
+ icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
+ else
+ icache_latency = icachePort.sendAtomic(&ifetch_pkt);
- assert(!ifetch_pkt.isError());
+ assert(!ifetch_pkt.isError());
- // ifetch_req is initialized to read the instruction directly
- // into the CPU object's inst field.
- //}
+ // ifetch_req is initialized to read the instruction directly
+ // into the CPU object's inst field.
+ //}
+ }
preExecute();
@@ -763,16 +664,21 @@ AtomicSimpleCPU::tick()
curStaticInst->isFirstMicroop()))
instCnt++;
- if (simulate_stalls) {
- Tick icache_stall =
- icache_access ? icache_latency - ticks(1) : 0;
- Tick dcache_stall =
- dcache_access ? dcache_latency - ticks(1) : 0;
- Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1);
- if (ticks(stall_cycles) < (icache_stall + dcache_stall))
- latency += ticks(stall_cycles+1);
- else
- latency += ticks(stall_cycles);
+ Tick stall_ticks = 0;
+ if (simulate_inst_stalls && icache_access)
+ stall_ticks += icache_latency;
+
+ if (simulate_data_stalls && dcache_access)
+ stall_ticks += dcache_latency;
+
+ if (stall_ticks) {
+ Tick stall_cycles = stall_ticks / ticks(1);
+ Tick aligned_stall_ticks = ticks(stall_cycles);
+
+ if (aligned_stall_ticks < stall_ticks)
+ aligned_stall_ticks += 1;
+
+ latency += aligned_stall_ticks;
}
}
@@ -780,8 +686,12 @@ AtomicSimpleCPU::tick()
advancePC(fault);
}
+ // instruction takes at least one cycle
+ if (latency < ticks(1))
+ latency = ticks(1);
+
if (_status != Idle)
- tickEvent.schedule(curTick + latency);
+ schedule(tickEvent, curTick + latency);
}
@@ -799,38 +709,10 @@ AtomicSimpleCPU::printAddr(Addr a)
AtomicSimpleCPU *
AtomicSimpleCPUParams::create()
{
- AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
- params->name = name;
- params->numberOfThreads = 1;
- params->max_insts_any_thread = max_insts_any_thread;
- params->max_insts_all_threads = max_insts_all_threads;
- params->max_loads_any_thread = max_loads_any_thread;
- params->max_loads_all_threads = max_loads_all_threads;
- params->progress_interval = progress_interval;
- params->deferRegistration = defer_registration;
- params->phase = phase;
- params->clock = clock;
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
- params->width = width;
- params->simulate_stalls = simulate_stalls;
- params->system = system;
- params->cpu_id = cpu_id;
- params->tracer = tracer;
-
- params->itb = itb;
- params->dtb = dtb;
-#if FULL_SYSTEM
- params->profile = profile;
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
+ numThreads = 1;
+#if !FULL_SYSTEM
if (workload.size() != 1)
panic("only one workload allowed");
- params->process = workload[0];
#endif
-
- AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
- return cpu;
+ return new AtomicSimpleCPU(this);
}
diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh
index 19bc0e13b..190097637 100644
--- a/src/cpu/simple/atomic.hh
+++ b/src/cpu/simple/atomic.hh
@@ -32,34 +32,17 @@
#define __CPU_SIMPLE_ATOMIC_HH__
#include "cpu/simple/base.hh"
+#include "params/AtomicSimpleCPU.hh"
class AtomicSimpleCPU : public BaseSimpleCPU
{
public:
- struct Params : public BaseSimpleCPU::Params {
- int width;
- bool simulate_stalls;
- };
-
- AtomicSimpleCPU(Params *params);
+ AtomicSimpleCPU(AtomicSimpleCPUParams *params);
virtual ~AtomicSimpleCPU();
virtual void init();
- public:
- //
- enum Status {
- Running,
- Idle,
- SwitchedOut
- };
-
- protected:
- Status _status;
-
- Status status() const { return _status; }
-
private:
struct TickEvent : public Event
@@ -74,7 +57,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU
TickEvent tickEvent;
const int width;
- const bool simulate_stalls;
+ const bool simulate_data_stalls;
+ const bool simulate_inst_stalls;
// main simulation loop (one cycle)
void tick();
@@ -152,11 +136,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU
template <class T>
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
- Fault translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
- Fault translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
/**
* Print state of address in memory system via PrintReq (for
* debugging).
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
index 4a91a9e12..348d2392f 100644
--- a/src/cpu/simple/base.cc
+++ b/src/cpu/simple/base.cc
@@ -31,6 +31,7 @@
#include "arch/utility.hh"
#include "arch/faults.hh"
#include "base/cprintf.hh"
+#include "base/cp_annotate.hh"
#include "base/inifile.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
@@ -65,16 +66,18 @@
#include "mem/mem_object.hh"
#endif // FULL_SYSTEM
+#include "params/BaseSimpleCPU.hh"
+
using namespace std;
using namespace TheISA;
-BaseSimpleCPU::BaseSimpleCPU(Params *p)
+BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
: BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
{
#if FULL_SYSTEM
thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
#else
- thread = new SimpleThread(this, /* thread_num */ 0, p->process,
+ thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0],
p->itb, p->dtb, /* asid */ 0);
#endif // !FULL_SYSTEM
@@ -174,12 +177,13 @@ void
BaseSimpleCPU::resetStats()
{
// startNumInst = numInst;
- // notIdleFraction = (_status != Idle);
+ notIdleFraction = (_status != Idle);
}
void
BaseSimpleCPU::serialize(ostream &os)
{
+ SERIALIZE_ENUM(_status);
BaseCPU::serialize(os);
// SERIALIZE_SCALAR(inst);
nameOut(os, csprintf("%s.xc.0", name()));
@@ -189,6 +193,7 @@ BaseSimpleCPU::serialize(ostream &os)
void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
+ UNSERIALIZE_ENUM(_status);
BaseCPU::unserialize(cp, section);
// UNSERIALIZE_SCALAR(inst);
thread->unserialize(cp, csprintf("%s.xc.0", section));
@@ -299,14 +304,13 @@ BaseSimpleCPU::dbg_vtophys(Addr addr)
#if FULL_SYSTEM
void
-BaseSimpleCPU::post_interrupt(int int_num, int index)
+BaseSimpleCPU::wakeup()
{
- BaseCPU::post_interrupt(int_num, index);
+ if (thread->status() != ThreadContext::Suspended)
+ return;
- if (thread->status() == ThreadContext::Suspended) {
- DPRINTF(Quiesce,"Suspended Processor awoke\n");
- thread->activate();
- }
+ DPRINTF(Quiesce,"Suspended Processor awoke\n");
+ thread->activate();
}
#endif // FULL_SYSTEM
@@ -314,11 +318,12 @@ void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
- if (check_interrupts(tc)) {
- Fault interrupt = interrupts.getInterrupt(tc);
+ if (checkInterrupts(tc)) {
+ Fault interrupt = interrupts->getInterrupt(tc);
if (interrupt != NoFault) {
- interrupts.updateIntrInfo(tc);
+ predecoder.reset();
+ interrupts->updateIntrInfo(tc);
interrupt->invoke(tc);
}
}
@@ -326,7 +331,7 @@ BaseSimpleCPU::checkForInterrupts()
}
-Fault
+void
BaseSimpleCPU::setupFetchRequest(Request *req)
{
Addr threadPC = thread->readPC();
@@ -342,10 +347,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req)
Addr fetchPC = (threadPC & PCMask) + fetchOffset;
req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC);
-
- Fault fault = thread->translateInstReq(req);
-
- return fault;
}
@@ -364,9 +365,13 @@ BaseSimpleCPU::preExecute()
// decode the instruction
inst = gtoh(inst);
- //If we're not in the middle of a macro instruction
- if (!curMacroStaticInst) {
+ MicroPC upc = thread->readMicroPC();
+ if (isRomMicroPC(upc)) {
+ stayAtPC = false;
+ curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst);
+ } else if (!curMacroStaticInst) {
+ //We're not in the middle of a macro instruction
StaticInstPtr instPtr = NULL;
//Predecode, ie bundle up an ExtMachInst
@@ -397,23 +402,22 @@ BaseSimpleCPU::preExecute()
//out micro ops
if (instPtr && instPtr->isMacroop()) {
curMacroStaticInst = instPtr;
- curStaticInst = curMacroStaticInst->
- fetchMicroop(thread->readMicroPC());
+ curStaticInst = curMacroStaticInst->fetchMicroop(upc);
} else {
curStaticInst = instPtr;
}
} else {
//Read the next micro op from the macro op
- curStaticInst = curMacroStaticInst->
- fetchMicroop(thread->readMicroPC());
+ curStaticInst = curMacroStaticInst->fetchMicroop(upc);
}
//If we decoded an instruction this "tick", record information about it.
if(curStaticInst)
{
#if TRACING_ON
- traceData = tracer->getInstRecord(curTick, tc, curStaticInst,
- thread->readPC());
+ traceData = tracer->getInstRecord(curTick, tc,
+ curStaticInst, thread->readPC(),
+ curMacroStaticInst, thread->readMicroPC());
DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
curStaticInst->getName(), curStaticInst->machInst);
@@ -447,6 +451,10 @@ BaseSimpleCPU::postExecute()
comLoadEventQueue[0]->serviceEvents(numLoad);
}
+ if (CPA::available()) {
+ CPA::cpa()->swAutoBegin(tc, thread->readNextPC());
+ }
+
traceFunctions(thread->readPC());
if (traceData) {
@@ -465,22 +473,21 @@ BaseSimpleCPU::advancePC(Fault fault)
if (fault != NoFault) {
curMacroStaticInst = StaticInst::nullStaticInstPtr;
predecoder.reset();
- thread->setMicroPC(0);
- thread->setNextMicroPC(1);
fault->invoke(tc);
} else {
//If we're at the last micro op for this instruction
if (curStaticInst && curStaticInst->isLastMicroop()) {
- //We should be working with a macro op
- assert(curMacroStaticInst);
+ //We should be working with a macro op or be in the ROM
+ assert(curMacroStaticInst ||
+ isRomMicroPC(thread->readMicroPC()));
//Close out this macro op, and clean up the
//microcode state
curMacroStaticInst = StaticInst::nullStaticInstPtr;
- thread->setMicroPC(0);
- thread->setNextMicroPC(1);
+ thread->setMicroPC(normalMicroPC(0));
+ thread->setNextMicroPC(normalMicroPC(1));
}
//If we're still in a macro op
- if (curMacroStaticInst) {
+ if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) {
//Advance the micro pc
thread->setMicroPC(thread->readNextMicroPC());
//Advance the "next" micro pc. Note that there are no delay
diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh
index 918965fdb..e80606388 100644
--- a/src/cpu/simple/base.hh
+++ b/src/cpu/simple/base.hh
@@ -76,6 +76,8 @@ namespace Trace {
class InstRecord;
}
+class BaseSimpleCPUParams;
+
class BaseSimpleCPU : public BaseCPU
{
@@ -96,7 +98,7 @@ class BaseSimpleCPU : public BaseCPU
}
public:
- void post_interrupt(int int_num, int index);
+ void wakeup();
void zero_fill_64(Addr addr) {
static int warned = 0;
@@ -107,15 +109,7 @@ class BaseSimpleCPU : public BaseCPU
};
public:
- struct Params : public BaseCPU::Params
- {
- TheISA::ITB *itb;
- TheISA::DTB *dtb;
-#if !FULL_SYSTEM
- Process *process;
-#endif
- };
- BaseSimpleCPU(Params *params);
+ BaseSimpleCPU(BaseSimpleCPUParams *params);
virtual ~BaseSimpleCPU();
public:
@@ -127,7 +121,22 @@ class BaseSimpleCPU : public BaseCPU
*/
ThreadContext *tc;
protected:
- int cpuId;
+
+ enum Status {
+ Idle,
+ Running,
+ ITBWaitResponse,
+ IcacheRetry,
+ IcacheWaitResponse,
+ IcacheWaitSwitch,
+ DTBWaitResponse,
+ DcacheRetry,
+ DcacheWaitResponse,
+ DcacheWaitSwitch,
+ SwitchedOut
+ };
+
+ Status _status;
public:
@@ -153,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU
bool stayAtPC;
void checkForInterrupts();
- Fault setupFetchRequest(Request *req);
+ void setupFetchRequest(Request *req);
void preExecute();
void postExecute();
void advancePC(Fault fault);
@@ -168,7 +177,7 @@ class BaseSimpleCPU : public BaseCPU
// number of simulated instructions
Counter numInst;
Counter startNumInst;
- Stats::Scalar<> numInsts;
+ Stats::Scalar numInsts;
void countInst()
{
@@ -187,30 +196,30 @@ class BaseSimpleCPU : public BaseCPU
static const Addr PCMask = ~((Addr)sizeof(TheISA::MachInst) - 1);
// number of simulated memory references
- Stats::Scalar<> numMemRefs;
+ Stats::Scalar numMemRefs;
// number of simulated loads
Counter numLoad;
Counter startNumLoad;
// number of idle cycles
- Stats::Average<> notIdleFraction;
+ Stats::Average notIdleFraction;
Stats::Formula idleFraction;
// number of cycles stalled for I-cache responses
- Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar icacheStallCycles;
Counter lastIcacheStall;
// number of cycles stalled for I-cache retries
- Stats::Scalar<> icacheRetryCycles;
+ Stats::Scalar icacheRetryCycles;
Counter lastIcacheRetry;
// number of cycles stalled for D-cache responses
- Stats::Scalar<> dcacheStallCycles;
+ Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
// number of cycles stalled for D-cache retries
- Stats::Scalar<> dcacheRetryCycles;
+ Stats::Scalar dcacheRetryCycles;
Counter lastDcacheRetry;
virtual void serialize(std::ostream &os);
@@ -219,7 +228,7 @@ class BaseSimpleCPU : public BaseCPU
// These functions are only used in CPU models that split
// effective address computation from the actual memory access.
void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); }
- Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n");
+ Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n");
M5_DUMMY_RETURN}
void prefetch(Addr addr, unsigned flags)
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index a76824ff3..a8f86f8d2 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -57,13 +57,12 @@ void
TimingSimpleCPU::init()
{
BaseCPU::init();
- cpuId = tc->readCpuId();
#if FULL_SYSTEM
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, cpuId);
+ TheISA::initCPU(tc, _cpuId);
}
#endif
}
@@ -101,11 +100,12 @@ void
TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
{
pkt = _pkt;
- Event::schedule(t);
+ cpu->schedule(this, t);
}
-TimingSimpleCPU::TimingSimpleCPU(Params *p)
- : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
+TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
+ : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
+ dcachePort(this, p->clock), fetchEvent(this)
{
_status = Idle;
@@ -114,7 +114,6 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
ifetch_pkt = dcache_pkt = NULL;
drainEvent = NULL;
- fetchEvent = NULL;
previousTick = 0;
changeState(SimObject::Running);
}
@@ -145,7 +144,7 @@ TimingSimpleCPU::drain(Event *drain_event)
{
// TimingSimpleCPU is ready to drain if it's not waiting for
// an access to complete.
- if (status() == Idle || status() == Running || status() == SwitchedOut) {
+ if (_status == Idle || _status == Running || _status == SwitchedOut) {
changeState(SimObject::Drained);
return 0;
} else {
@@ -162,15 +161,10 @@ TimingSimpleCPU::resume()
if (_status != SwitchedOut && _status != Idle) {
assert(system->getMemoryMode() == Enums::timing);
- // Delete the old event if it existed.
- if (fetchEvent) {
- if (fetchEvent->scheduled())
- fetchEvent->deschedule();
+ if (fetchEvent.scheduled())
+ deschedule(fetchEvent);
- delete fetchEvent;
- }
-
- fetchEvent = new FetchEvent(this, nextCycle());
+ schedule(fetchEvent, nextCycle());
}
changeState(SimObject::Running);
@@ -179,14 +173,14 @@ TimingSimpleCPU::resume()
void
TimingSimpleCPU::switchOut()
{
- assert(status() == Running || status() == Idle);
+ assert(_status == Running || _status == Idle);
_status = SwitchedOut;
numCycles += tickToCycles(curTick - previousTick);
// If we've been scheduled to resume but are then told to switch out,
// we'll need to cancel it.
- if (fetchEvent && fetchEvent->scheduled())
- fetchEvent->deschedule();
+ if (fetchEvent.scheduled())
+ deschedule(fetchEvent);
}
@@ -209,7 +203,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
_status = Idle;
}
assert(threadContexts.size() == 1);
- cpuId = tc->readCpuId();
previousTick = curTick;
}
@@ -228,7 +221,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
_status = Running;
// kick things off by initiating the fetch of the next instruction
- fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay)));
+ schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
}
@@ -249,74 +242,239 @@ TimingSimpleCPU::suspendContext(int thread_num)
_status = Idle;
}
+bool
+TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
+{
+ RequestPtr req = pkt->req;
+ if (req->isMmapedIpr()) {
+ Tick delay;
+ delay = TheISA::handleIprRead(thread->getTC(), pkt);
+ new IprEvent(pkt, this, nextCycle(curTick + delay));
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ } else if (!dcachePort.sendTiming(pkt)) {
+ _status = DcacheRetry;
+ dcache_pkt = pkt;
+ } else {
+ _status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ dcache_pkt = NULL;
+ }
+ return dcache_pkt == NULL;
+}
-template <class T>
-Fault
-TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
+void
+TimingSimpleCPU::sendData(Fault fault, RequestPtr req,
+ uint8_t *data, uint64_t *res, bool read)
{
- Request *req =
- new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
- cpuId, /* thread ID */ 0);
+ _status = Running;
+ if (fault != NoFault) {
+ delete data;
+ delete req;
- if (traceData) {
- traceData->setAddr(req->getVaddr());
+ translationFault(fault);
+ return;
}
+ PacketPtr pkt;
+ buildPacket(pkt, req, read);
+ pkt->dataDynamic<uint8_t>(data);
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ assert(!dcache_pkt);
+ pkt->makeResponse();
+ completeDataAccess(pkt);
+ } else if (read) {
+ handleReadPacket(pkt);
+ } else {
+ bool do_access = true; // flag to suppress cache access
- // translate to physical address
- Fault fault = thread->translateDataReadReq(req);
+ if (req->isLocked()) {
+ do_access = TheISA::handleLockedWrite(thread, req);
+ } else if (req->isCondSwap()) {
+ assert(res);
+ req->setExtraData(*res);
+ }
- // Now do the access.
- if (fault == NoFault) {
- PacketPtr pkt =
- new Packet(req,
- (req->isLocked() ?
- MemCmd::LoadLockedReq : MemCmd::ReadReq),
- Packet::Broadcast);
- pkt->dataDynamic<T>(new T);
-
- if (req->isMmapedIpr()) {
- Tick delay;
- delay = TheISA::handleIprRead(thread->getTC(), pkt);
- new IprEvent(pkt, this, nextCycle(curTick + delay));
- _status = DcacheWaitResponse;
- dcache_pkt = NULL;
- } else if (!dcachePort.sendTiming(pkt)) {
- _status = DcacheRetry;
+ if (do_access) {
dcache_pkt = pkt;
+ handleWritePacket();
} else {
_status = DcacheWaitResponse;
- // memory system takes ownership of packet
- dcache_pkt = NULL;
+ completeDataAccess(pkt);
}
+ }
+}
- // This will need a new way to tell if it has a dcache attached.
- if (req->isUncacheable())
- recordEvent("Uncached Read");
+void
+TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read)
+{
+ _status = Running;
+ if (fault1 != NoFault || fault2 != NoFault) {
+ delete data;
+ delete req1;
+ delete req2;
+ if (fault1 != NoFault)
+ translationFault(fault1);
+ else if (fault2 != NoFault)
+ translationFault(fault2);
+ return;
+ }
+ PacketPtr pkt1, pkt2;
+ buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ assert(!dcache_pkt);
+ pkt1->makeResponse();
+ completeDataAccess(pkt1);
+ } else if (read) {
+ if (handleReadPacket(pkt1)) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ if (handleReadPacket(pkt2)) {
+ send_state = dynamic_cast<SplitFragmentSenderState *>(
+ pkt1->senderState);
+ send_state->clearFromParent();
+ }
+ }
} else {
- delete req;
+ dcache_pkt = pkt1;
+ if (handleWritePacket()) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ dcache_pkt = pkt2;
+ if (handleWritePacket()) {
+ send_state = dynamic_cast<SplitFragmentSenderState *>(
+ pkt1->senderState);
+ send_state->clearFromParent();
+ }
+ }
+ }
+}
+
+void
+TimingSimpleCPU::translationFault(Fault fault)
+{
+ numCycles += tickToCycles(curTick - previousTick);
+ previousTick = curTick;
+
+ if (traceData) {
+ // Since there was a fault, we shouldn't trace this instruction.
+ delete traceData;
+ traceData = NULL;
}
- return fault;
+ postExecute();
+
+ if (getState() == SimObject::Draining) {
+ advancePC(fault);
+ completeDrain();
+ } else {
+ advanceInst(fault);
+ }
}
+void
+TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
+{
+ MemCmd cmd;
+ if (read) {
+ cmd = MemCmd::ReadReq;
+ if (req->isLocked())
+ cmd = MemCmd::LoadLockedReq;
+ } else {
+ cmd = MemCmd::WriteReq;
+ if (req->isLocked()) {
+ cmd = MemCmd::StoreCondReq;
+ } else if (req->isSwap()) {
+ cmd = MemCmd::SwapReq;
+ }
+ }
+ pkt = new Packet(req, cmd, Packet::Broadcast);
+}
+
+void
+TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read)
+{
+ pkt1 = pkt2 = NULL;
+
+ assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
+
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ buildPacket(pkt1, req, read);
+ return;
+ }
+
+ buildPacket(pkt1, req1, read);
+ buildPacket(pkt2, req2, read);
+
+ req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
+ PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
+ Packet::Broadcast);
+
+ pkt->dataDynamic<uint8_t>(data);
+ pkt1->dataStatic<uint8_t>(data);
+ pkt2->dataStatic<uint8_t>(data + req1->getSize());
+
+ SplitMainSenderState * main_send_state = new SplitMainSenderState;
+ pkt->senderState = main_send_state;
+ main_send_state->fragments[0] = pkt1;
+ main_send_state->fragments[1] = pkt2;
+ main_send_state->outstanding = 2;
+ pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
+ pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
+}
+
+template <class T>
Fault
-TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
+TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
{
- Request *req =
- new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
+ Fault fault;
+ const int asid = 0;
+ const int thread_id = 0;
+ const Addr pc = thread->readPC();
+ int block_size = dcachePort.peerBlockSize();
+ int data_size = sizeof(T);
+
+ RequestPtr req = new Request(asid, addr, data_size,
+ flags, pc, _cpuId, thread_id);
+
+ Addr split_addr = roundDown(addr + data_size - 1, block_size);
+ assert(split_addr <= addr || split_addr - addr < block_size);
+
+
+ _status = DTBWaitResponse;
+ if (split_addr > addr) {
+ RequestPtr req1, req2;
+ assert(!req->isLocked() && !req->isSwap());
+ req->splitOnVaddr(split_addr, req1, req2);
+
+ typedef SplitDataTranslation::WholeTranslationState WholeState;
+ WholeState *state = new WholeState(req1, req2, req,
+ (uint8_t *)(new T), true);
+ thread->dtb->translateTiming(req1, tc,
+ new SplitDataTranslation(this, 0, state), false);
+ thread->dtb->translateTiming(req2, tc,
+ new SplitDataTranslation(this, 1, state), false);
+ } else {
+ thread->dtb->translateTiming(req, tc,
+ new DataTranslation(this, (uint8_t *)(new T), NULL, true),
+ false);
+ }
if (traceData) {
- traceData->setAddr(vaddr);
+ traceData->setData(data);
+ traceData->setAddr(addr);
}
- Fault fault = thread->translateDataWriteReq(req);
+ // This will need a new way to tell if it has a dcache attached.
+ if (req->isUncacheable())
+ recordEvent("Uncached Read");
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
+ return NoFault;
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -369,92 +527,75 @@ TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
return read(addr, (uint32_t&)data, flags);
}
+bool
+TimingSimpleCPU::handleWritePacket()
+{
+ RequestPtr req = dcache_pkt->req;
+ if (req->isMmapedIpr()) {
+ Tick delay;
+ delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
+ new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ } else if (!dcachePort.sendTiming(dcache_pkt)) {
+ _status = DcacheRetry;
+ } else {
+ _status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ dcache_pkt = NULL;
+ }
+ return dcache_pkt == NULL;
+}
template <class T>
Fault
TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- Request *req =
- new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
- cpuId, /* thread ID */ 0);
+ const int asid = 0;
+ const int thread_id = 0;
+ const Addr pc = thread->readPC();
+ int block_size = dcachePort.peerBlockSize();
+ int data_size = sizeof(T);
+
+ RequestPtr req = new Request(asid, addr, data_size,
+ flags, pc, _cpuId, thread_id);
+
+ Addr split_addr = roundDown(addr + data_size - 1, block_size);
+ assert(split_addr <= addr || split_addr - addr < block_size);
+
+ T *dataP = new T;
+ *dataP = TheISA::htog(data);
+ _status = DTBWaitResponse;
+ if (split_addr > addr) {
+ RequestPtr req1, req2;
+ assert(!req->isLocked() && !req->isSwap());
+ req->splitOnVaddr(split_addr, req1, req2);
+
+ typedef SplitDataTranslation::WholeTranslationState WholeState;
+ WholeState *state = new WholeState(req1, req2, req,
+ (uint8_t *)dataP, false);
+ thread->dtb->translateTiming(req1, tc,
+ new SplitDataTranslation(this, 0, state), true);
+ thread->dtb->translateTiming(req2, tc,
+ new SplitDataTranslation(this, 1, state), true);
+ } else {
+ thread->dtb->translateTiming(req, tc,
+ new DataTranslation(this, (uint8_t *)dataP, res, false),
+ true);
+ }
if (traceData) {
traceData->setAddr(req->getVaddr());
+ traceData->setData(data);
}
- // translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
-
- // Now do the access.
- if (fault == NoFault) {
- MemCmd cmd = MemCmd::WriteReq; // default
- bool do_access = true; // flag to suppress cache access
-
- if (req->isLocked()) {
- cmd = MemCmd::StoreCondReq;
- do_access = TheISA::handleLockedWrite(thread, req);
- } else if (req->isSwap()) {
- cmd = MemCmd::SwapReq;
- if (req->isCondSwap()) {
- assert(res);
- req->setExtraData(*res);
- }
- }
-
- // Note: need to allocate dcache_pkt even if do_access is
- // false, as it's used unconditionally to call completeAcc().
- assert(dcache_pkt == NULL);
- dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
- dcache_pkt->allocate();
- dcache_pkt->set(data);
-
- if (do_access) {
- if (req->isMmapedIpr()) {
- Tick delay;
- dcache_pkt->set(htog(data));
- delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
- new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
- _status = DcacheWaitResponse;
- dcache_pkt = NULL;
- } else if (!dcachePort.sendTiming(dcache_pkt)) {
- _status = DcacheRetry;
- } else {
- _status = DcacheWaitResponse;
- // memory system takes ownership of packet
- dcache_pkt = NULL;
- }
- }
- // This will need a new way to tell if it's hooked up to a cache or not.
- if (req->isUncacheable())
- recordEvent("Uncached Write");
- } else {
- delete req;
- }
-
+ // This will need a new way to tell if it's hooked up to a cache or not.
+ if (req->isUncacheable())
+ recordEvent("Uncached Write");
// If the write needs to have a fault on the access, consider calling
// changeStatus() and changing it to "bad addr write" or something.
- return fault;
-}
-
-Fault
-TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- Request *req =
- new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- Fault fault = thread->translateDataWriteReq(req);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
+ return NoFault;
}
@@ -524,14 +665,31 @@ TimingSimpleCPU::fetch()
checkPcEventQueue();
- Request *ifetch_req = new Request();
- ifetch_req->setThreadContext(cpuId, /* thread ID */ 0);
- Fault fault = setupFetchRequest(ifetch_req);
+ bool fromRom = isRomMicroPC(thread->readMicroPC());
- ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
- ifetch_pkt->dataStatic(&inst);
+ if (!fromRom && !curMacroStaticInst) {
+ Request *ifetch_req = new Request();
+ ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
+ setupFetchRequest(ifetch_req);
+ thread->itb->translateTiming(ifetch_req, tc,
+ &fetchTranslation);
+ } else {
+ _status = IcacheWaitResponse;
+ completeIfetch(NULL);
+ numCycles += tickToCycles(curTick - previousTick);
+ previousTick = curTick;
+ }
+}
+
+
+void
+TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
+{
if (fault == NoFault) {
+ ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
+ ifetch_pkt->dataStatic(&inst);
+
if (!icachePort.sendTiming(ifetch_pkt)) {
// Need to wait for retry
_status = IcacheRetry;
@@ -542,8 +700,7 @@ TimingSimpleCPU::fetch()
ifetch_pkt = NULL;
}
} else {
- delete ifetch_req;
- delete ifetch_pkt;
+ delete req;
// fetch fault: advance directly to next instruction (fault handler)
advanceInst(fault);
}
@@ -556,7 +713,8 @@ TimingSimpleCPU::fetch()
void
TimingSimpleCPU::advanceInst(Fault fault)
{
- advancePC(fault);
+ if (fault != NoFault || !stayAtPC)
+ advancePC(fault);
if (_status == Running) {
// kick off fetch of next instruction... callback from icache
@@ -574,7 +732,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
// received a response from the icache: execute the received
// instruction
- assert(!pkt->isError());
+
+ assert(!pkt || !pkt->isError());
assert(_status == IcacheWaitResponse);
_status = Running;
@@ -583,41 +742,27 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
previousTick = curTick;
if (getState() == SimObject::Draining) {
- delete pkt->req;
- delete pkt;
+ if (pkt) {
+ delete pkt->req;
+ delete pkt;
+ }
completeDrain();
return;
}
preExecute();
- if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
+ if (curStaticInst &&
+ curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
// load or store: just send to dcache
Fault fault = curStaticInst->initiateAcc(this, traceData);
if (_status != Running) {
// instruction will complete in dcache response callback
- assert(_status == DcacheWaitResponse || _status == DcacheRetry);
+ assert(_status == DcacheWaitResponse ||
+ _status == DcacheRetry || DTBWaitResponse);
assert(fault == NoFault);
} else {
- if (fault == NoFault) {
- // Note that ARM can have NULL packets if the instruction gets
- // squashed due to predication
- // early fail on store conditional: complete now
- assert(dcache_pkt != NULL || THE_ISA == ARM_ISA);
-
- fault = curStaticInst->completeAcc(dcache_pkt, this,
- traceData);
- if (dcache_pkt != NULL)
- {
- delete dcache_pkt->req;
- delete dcache_pkt;
- dcache_pkt = NULL;
- }
-
- // keep an instruction count
- if (fault == NoFault)
- countInst();
- } else if (traceData) {
+ if (fault != NoFault && traceData) {
// If there was a fault, we shouldn't trace this instruction.
delete traceData;
traceData = NULL;
@@ -630,7 +775,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
instCnt++;
advanceInst(fault);
}
- } else {
+ } else if (curStaticInst) {
// non-memory instruction: execute completely now
Fault fault = curStaticInst->execute(this, traceData);
@@ -649,10 +794,14 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
curStaticInst->isFirstMicroop()))
instCnt++;
advanceInst(fault);
+ } else {
+ advanceInst(NoFault);
}
- delete pkt->req;
- delete pkt;
+ if (pkt) {
+ delete pkt->req;
+ delete pkt;
+ }
}
void
@@ -707,12 +856,38 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
// received a response from the dcache: complete the load or store
// instruction
assert(!pkt->isError());
- assert(_status == DcacheWaitResponse);
- _status = Running;
numCycles += tickToCycles(curTick - previousTick);
previousTick = curTick;
+ if (pkt->senderState) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
+ assert(send_state);
+ delete pkt->req;
+ delete pkt;
+ PacketPtr big_pkt = send_state->bigPkt;
+ delete send_state;
+
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
+ assert(main_send_state);
+ // Record the fact that this packet is no longer outstanding.
+ assert(main_send_state->outstanding != 0);
+ main_send_state->outstanding--;
+
+ if (main_send_state->outstanding) {
+ return;
+ } else {
+ delete main_send_state;
+ big_pkt->senderState = NULL;
+ pkt = big_pkt;
+ }
+ }
+
+ assert(_status == DcacheWaitResponse || _status == DTBWaitResponse);
+ _status = Running;
+
Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
// keep an instruction count
@@ -724,7 +899,9 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
traceData = NULL;
}
- if (pkt->isRead() && pkt->isLocked()) {
+ // the locked flag may be cleared on the response packet, so check
+ // pkt->req and not pkt to see if it was a load-locked
+ if (pkt->isRead() && pkt->req->isLocked()) {
TheISA::handleLockedRead(thread, pkt->req);
}
@@ -760,7 +937,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port)
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
- cpu->tcBase()->connectMemPorts();
+ cpu->tcBase()->connectMemPorts(cpu->tcBase());
#endif
}
@@ -771,10 +948,11 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
// delay processing of returned data until next CPU clock edge
Tick next_tick = cpu->nextCycle(curTick);
- if (next_tick == curTick)
+ if (next_tick == curTick) {
cpu->completeDataAccess(pkt);
- else
+ } else {
tickEvent.schedule(pkt, next_tick);
+ }
return true;
}
@@ -804,17 +982,47 @@ TimingSimpleCPU::DcachePort::recvRetry()
assert(cpu->dcache_pkt != NULL);
assert(cpu->_status == DcacheRetry);
PacketPtr tmp = cpu->dcache_pkt;
- if (sendTiming(tmp)) {
+ if (tmp->senderState) {
+ // This is a packet from a split access.
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
+ assert(send_state);
+ PacketPtr big_pkt = send_state->bigPkt;
+
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
+ assert(main_send_state);
+
+ if (sendTiming(tmp)) {
+ // If we were able to send without retrying, record that fact
+ // and try sending the other fragment.
+ send_state->clearFromParent();
+ int other_index = main_send_state->getPendingFragment();
+ if (other_index > 0) {
+ tmp = main_send_state->fragments[other_index];
+ cpu->dcache_pkt = tmp;
+ if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
+ (big_pkt->isWrite() && cpu->handleWritePacket())) {
+ main_send_state->fragments[other_index] = NULL;
+ }
+ } else {
+ cpu->_status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ cpu->dcache_pkt = NULL;
+ }
+ }
+ } else if (sendTiming(tmp)) {
cpu->_status = DcacheWaitResponse;
// memory system takes ownership of packet
cpu->dcache_pkt = NULL;
}
}
-TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t)
- : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu)
+TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
+ Tick t)
+ : pkt(_pkt), cpu(_cpu)
{
- schedule(t);
+ cpu->schedule(this, t);
}
void
@@ -844,36 +1052,10 @@ TimingSimpleCPU::printAddr(Addr a)
TimingSimpleCPU *
TimingSimpleCPUParams::create()
{
- TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
- params->name = name;
- params->numberOfThreads = 1;
- params->max_insts_any_thread = max_insts_any_thread;
- params->max_insts_all_threads = max_insts_all_threads;
- params->max_loads_any_thread = max_loads_any_thread;
- params->max_loads_all_threads = max_loads_all_threads;
- params->progress_interval = progress_interval;
- params->deferRegistration = defer_registration;
- params->clock = clock;
- params->phase = phase;
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
- params->system = system;
- params->cpu_id = cpu_id;
- params->tracer = tracer;
-
- params->itb = itb;
- params->dtb = dtb;
-#if FULL_SYSTEM
- params->profile = profile;
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
+ numThreads = 1;
+#if !FULL_SYSTEM
if (workload.size() != 1)
panic("only one workload allowed");
- params->process = workload[0];
#endif
-
- TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
- return cpu;
+ return new TimingSimpleCPU(this);
}
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
index f8b77604a..a02ec48c9 100644
--- a/src/cpu/simple/timing.hh
+++ b/src/cpu/simple/timing.hh
@@ -33,40 +33,181 @@
#include "cpu/simple/base.hh"
+#include "params/TimingSimpleCPU.hh"
+
class TimingSimpleCPU : public BaseSimpleCPU
{
public:
- struct Params : public BaseSimpleCPU::Params {
- };
-
- TimingSimpleCPU(Params *params);
+ TimingSimpleCPU(TimingSimpleCPUParams * params);
virtual ~TimingSimpleCPU();
virtual void init();
public:
- //
- enum Status {
- Idle,
- Running,
- IcacheRetry,
- IcacheWaitResponse,
- IcacheWaitSwitch,
- DcacheRetry,
- DcacheWaitResponse,
- DcacheWaitSwitch,
- SwitchedOut
+ Event *drainEvent;
+
+ private:
+
+ /*
+ * If an access needs to be broken into fragments, currently at most two,
+ * the the following two classes are used as the sender state of the
+ * packets so the CPU can keep track of everything. In the main packet
+ * sender state, there's an array with a spot for each fragment. If a
+ * fragment has already been accepted by the CPU, aka isn't waiting for
+ * a retry, it's pointer is NULL. After each fragment has successfully
+ * been processed, the "outstanding" counter is decremented. Once the
+ * count is zero, the entire larger access is complete.
+ */
+ class SplitMainSenderState : public Packet::SenderState
+ {
+ public:
+ int outstanding;
+ PacketPtr fragments[2];
+
+ int
+ getPendingFragment()
+ {
+ if (fragments[0]) {
+ return 0;
+ } else if (fragments[1]) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
};
- protected:
- Status _status;
+ class SplitFragmentSenderState : public Packet::SenderState
+ {
+ public:
+ SplitFragmentSenderState(PacketPtr _bigPkt, int _index) :
+ bigPkt(_bigPkt), index(_index)
+ {}
+ PacketPtr bigPkt;
+ int index;
+
+ void
+ clearFromParent()
+ {
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(bigPkt->senderState);
+ main_send_state->fragments[index] = NULL;
+ }
+ };
- Status status() const { return _status; }
+ class FetchTranslation : public BaseTLB::Translation
+ {
+ protected:
+ TimingSimpleCPU *cpu;
- Event *drainEvent;
+ public:
+ FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu)
+ {}
- private:
+ void finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write)
+ {
+ cpu->sendFetch(fault, req, tc);
+ }
+ };
+ FetchTranslation fetchTranslation;
+
+ class DataTranslation : public BaseTLB::Translation
+ {
+ protected:
+ TimingSimpleCPU *cpu;
+ uint8_t *data;
+ uint64_t *res;
+ bool read;
+
+ public:
+ DataTranslation(TimingSimpleCPU *_cpu,
+ uint8_t *_data, uint64_t *_res, bool _read) :
+ cpu(_cpu), data(_data), res(_res), read(_read)
+ {}
+
+ void
+ finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write)
+ {
+ cpu->sendData(fault, req, data, res, read);
+ delete this;
+ }
+ };
+
+ class SplitDataTranslation : public BaseTLB::Translation
+ {
+ public:
+ struct WholeTranslationState
+ {
+ public:
+ int outstanding;
+ RequestPtr requests[2];
+ RequestPtr mainReq;
+ Fault faults[2];
+ uint8_t *data;
+ bool read;
+
+ WholeTranslationState(RequestPtr req1, RequestPtr req2,
+ RequestPtr main, uint8_t *_data, bool _read)
+ {
+ outstanding = 2;
+ requests[0] = req1;
+ requests[1] = req2;
+ mainReq = main;
+ faults[0] = faults[1] = NoFault;
+ data = _data;
+ read = _read;
+ }
+ };
+
+ TimingSimpleCPU *cpu;
+ int index;
+ WholeTranslationState *state;
+
+ SplitDataTranslation(TimingSimpleCPU *_cpu, int _index,
+ WholeTranslationState *_state) :
+ cpu(_cpu), index(_index), state(_state)
+ {}
+
+ void
+ finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write)
+ {
+ assert(state);
+ assert(state->outstanding);
+ state->faults[index] = fault;
+ if (--state->outstanding == 0) {
+ cpu->sendSplitData(state->faults[0],
+ state->faults[1],
+ state->requests[0],
+ state->requests[1],
+ state->mainReq,
+ state->data,
+ state->read);
+ delete state;
+ }
+ delete this;
+ }
+ };
+
+ void sendData(Fault fault, RequestPtr req,
+ uint8_t *data, uint64_t *res, bool read);
+ void sendSplitData(Fault fault1, Fault fault2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read);
+
+ void translationFault(Fault fault);
+
+ void buildPacket(PacketPtr &pkt, RequestPtr req, bool read);
+ void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read);
+
+ bool handleReadPacket(PacketPtr pkt);
+ // This function always implicitly uses dcache_pkt.
+ bool handleWritePacket();
class CpuPort : public Port
{
@@ -99,8 +240,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
PacketPtr pkt;
TimingSimpleCPU *cpu;
- TickEvent(TimingSimpleCPU *_cpu)
- :Event(&mainEventQueue), cpu(_cpu) {}
+ TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {}
const char *description() const { return "Timing CPU tick"; }
void schedule(PacketPtr _pkt, Tick t);
};
@@ -189,18 +329,13 @@ class TimingSimpleCPU : public BaseSimpleCPU
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
- Fault translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
template <class T>
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
- Fault translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
void fetch();
+ void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc);
void completeIfetch(PacketPtr );
- void completeDataAccess(PacketPtr );
+ void completeDataAccess(PacketPtr pkt);
void advanceInst(Fault fault);
/**
@@ -212,7 +347,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
private:
typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent;
- FetchEvent *fetchEvent;
+ FetchEvent fetchEvent;
struct IprEvent : Event {
Packet *pkt;
diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc
index 93772fbe1..af0bb4490 100644
--- a/src/cpu/simple_thread.cc
+++ b/src/cpu/simple_thread.cc
@@ -37,9 +37,11 @@
#include "cpu/base.hh"
#include "cpu/simple_thread.hh"
#include "cpu/thread_context.hh"
+#include "params/BaseCPU.hh"
#if FULL_SYSTEM
#include "arch/kernel_stats.hh"
+#include "arch/stacktrace.hh"
#include "base/callback.hh"
#include "base/cprintf.hh"
#include "base/output.hh"
@@ -48,11 +50,10 @@
#include "cpu/quiesce_event.hh"
#include "sim/serialize.hh"
#include "sim/sim_exit.hh"
-#include "arch/stacktrace.hh"
#else
+#include "mem/translating_port.hh"
#include "sim/process.hh"
#include "sim/system.hh"
-#include "mem/translating_port.hh"
#endif
using namespace std;
@@ -62,7 +63,7 @@ using namespace std;
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
TheISA::ITB *_itb, TheISA::DTB *_dtb,
bool use_kernel_stats)
- : ThreadState(_cpu, -1, _thread_num), cpu(_cpu), system(_sys), itb(_itb),
+ : ThreadState(_cpu, _thread_num), cpu(_cpu), system(_sys), itb(_itb),
dtb(_dtb)
{
@@ -72,7 +73,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
regs.clear();
- if (cpu->params->profile) {
+ if (cpu->params()->profile) {
profile = new FunctionProfile(system->kernelSymtab);
Callback *cb =
new MakeCallback<SimpleThread,
@@ -86,16 +87,13 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
profileNode = &dummyNode;
profilePC = 3;
- if (use_kernel_stats) {
+ if (use_kernel_stats)
kernelStats = new TheISA::Kernel::Statistics(system);
- } else {
- kernelStats = NULL;
- }
}
#else
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process,
TheISA::ITB *_itb, TheISA::DTB *_dtb, int _asid)
- : ThreadState(_cpu, -1, _thread_num, _process, _asid),
+ : ThreadState(_cpu, _thread_num, _process, _asid),
cpu(_cpu), itb(_itb), dtb(_dtb)
{
regs.clear();
@@ -106,9 +104,9 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process,
SimpleThread::SimpleThread()
#if FULL_SYSTEM
- : ThreadState(NULL, -1, -1)
+ : ThreadState(NULL, -1)
#else
- : ThreadState(NULL, -1, -1, NULL, -1)
+ : ThreadState(NULL, -1, NULL, -1)
#endif
{
tc = new ProxyThreadContext<SimpleThread>(this);
@@ -180,18 +178,20 @@ SimpleThread::copyState(ThreadContext *oldContext)
// copy over functional state
_status = oldContext->status();
copyArchRegs(oldContext);
- cpuId = oldContext->readCpuId();
#if !FULL_SYSTEM
funcExeInst = oldContext->readFuncExeInst();
#endif
inst = oldContext->getInst();
+
+ _threadId = oldContext->threadId();
+ _contextId = oldContext->contextId();
}
void
SimpleThread::serialize(ostream &os)
{
ThreadState::serialize(os);
- regs.serialize(os);
+ regs.serialize(cpu, os);
// thread_num and cpu_id are deterministic from the config
}
@@ -200,7 +200,7 @@ void
SimpleThread::unserialize(Checkpoint *cp, const std::string &section)
{
ThreadState::unserialize(cp, section);
- regs.unserialize(cp, section);
+ regs.unserialize(cpu, cp, section);
// thread_num and cpu_id are deterministic from the config
}
@@ -222,14 +222,14 @@ SimpleThread::activate(int delay)
lastActivate = curTick;
// if (status() == ThreadContext::Unallocated) {
-// cpu->activateWhenReady(tid);
-// return;
+// cpu->activateWhenReady(_threadId);
+// return;
// }
_status = ThreadContext::Active;
// status() == Suspended
- cpu->activateContext(tid, delay);
+ cpu->activateContext(_threadId, delay);
}
void
@@ -243,14 +243,14 @@ SimpleThread::suspend()
/*
#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
- if (cpu->check_interrupts()) {
+ if (cpu->checkInterrupts()) {
assert(status() == ThreadContext::Active);
return;
}
#endif
*/
_status = ThreadContext::Suspended;
- cpu->suspendContext(tid);
+ cpu->suspendContext(_threadId);
}
void
@@ -260,7 +260,7 @@ SimpleThread::deallocate()
return;
_status = ThreadContext::Unallocated;
- cpu->deallocateContext(tid);
+ cpu->deallocateContext(_threadId);
}
void
@@ -270,7 +270,7 @@ SimpleThread::halt()
return;
_status = ThreadContext::Halted;
- cpu->haltContext(tid);
+ cpu->haltContext(_threadId);
}
@@ -289,26 +289,3 @@ SimpleThread::copyArchRegs(ThreadContext *src_tc)
TheISA::copyRegs(src_tc, tc);
}
-#if FULL_SYSTEM
-VirtualPort*
-SimpleThread::getVirtPort(ThreadContext *src_tc)
-{
- if (!src_tc)
- return virtPort;
-
- VirtualPort *vp = new VirtualPort("tc-vport", src_tc);
- connectToMemFunc(vp);
- return vp;
-}
-
-void
-SimpleThread::delVirtPort(VirtualPort *vp)
-{
- if (vp != virtPort) {
- vp->removeConn();
- delete vp;
- }
-}
-
-#endif
-
diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh
index fa80a283a..73929d362 100644
--- a/src/cpu/simple_thread.hh
+++ b/src/cpu/simple_thread.hh
@@ -34,7 +34,6 @@
#include "arch/isa_traits.hh"
#include "arch/regfile.hh"
-#include "arch/syscallreturn.hh"
#include "arch/tlb.hh"
#include "config/full_system.hh"
#include "cpu/thread_context.hh"
@@ -99,7 +98,7 @@ class SimpleThread : public ThreadState
typedef ThreadContext::Status Status;
protected:
- RegFile regs; // correct-path register context
+ RegFile regs; // correct-path register context
public:
// pointer to CPU associated with this SimpleThread
@@ -139,7 +138,7 @@ class SimpleThread : public ThreadState
/***************************************************************
* SimpleThread functions to provide CPU with access to various
- * state, and to provide address translation methods.
+ * state.
**************************************************************/
/** Returns the pointer to this SimpleThread's ThreadContext. Used
@@ -148,21 +147,6 @@ class SimpleThread : public ThreadState
*/
ThreadContext *getTC() { return tc; }
- Fault translateInstReq(RequestPtr &req)
- {
- return itb->translate(req, tc);
- }
-
- Fault translateDataReadReq(RequestPtr &req)
- {
- return dtb->translate(req, tc, false);
- }
-
- Fault translateDataWriteReq(RequestPtr &req)
- {
- return dtb->translate(req, tc, true);
- }
-
void demapPage(Addr vaddr, uint64_t asn)
{
itb->demapPage(vaddr, asn);
@@ -197,23 +181,20 @@ class SimpleThread : public ThreadState
BaseCPU *getCpuPtr() { return cpu; }
- int getThreadNum() { return tid; }
-
TheISA::ITB *getITBPtr() { return itb; }
TheISA::DTB *getDTBPtr() { return dtb; }
-#if FULL_SYSTEM
System *getSystemPtr() { return system; }
+#if FULL_SYSTEM
FunctionalPort *getPhysPort() { return physPort; }
- /** Return a virtual port. If no thread context is specified then a static
- * port is returned. Otherwise a port is created and returned. It must be
- * deleted by deleteVirtPort(). */
- VirtualPort *getVirtPort(ThreadContext *tc);
-
- void delVirtPort(VirtualPort *vp);
+ /** Return a virtual port. This port cannot be cached locally in an object.
+ * After a CPU switch it may point to the wrong memory object which could
+ * mean stale data.
+ */
+ VirtualPort *getVirtPort() { return virtPort; }
#endif
Status status() const { return _status; }
@@ -385,37 +366,11 @@ class SimpleThread : public ThreadState
{ storeCondFailures = sc_failures; }
#if !FULL_SYSTEM
- TheISA::IntReg getSyscallArg(int i)
- {
- assert(i < TheISA::NumArgumentRegs);
- return regs.readIntReg(TheISA::flattenIntIndex(getTC(),
- TheISA::ArgumentReg[i]));
- }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, TheISA::IntReg val)
- {
- assert(i < TheISA::NumArgumentRegs);
- regs.setIntReg(TheISA::flattenIntIndex(getTC(),
- TheISA::ArgumentReg[i]), val);
- }
-
- void setSyscallReturn(SyscallReturn return_value)
- {
- TheISA::setSyscallReturn(return_value, getTC());
- }
-
void syscall(int64_t callnum)
{
process->syscall(callnum, tc);
}
#endif
-
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- regs.changeContext(param, val);
- }
};
diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc
index 52a7ede03..01136bda1 100644
--- a/src/cpu/static_inst.cc
+++ b/src/cpu/static_inst.cc
@@ -40,11 +40,17 @@ StaticInst::DecodeCache StaticInst::decodeCache;
StaticInst::AddrDecodeCache StaticInst::addrDecodeCache;
StaticInst::cacheElement StaticInst::recentDecodes[2];
+using namespace std;
+
+StaticInst::~StaticInst()
+{
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+}
+
void
StaticInst::dumpDecodeCacheStats()
{
- using namespace std;
-
cerr << "Decode hash table stats @ " << curTick << ":" << endl;
cerr << "\tnum entries = " << decodeCache.size() << endl;
cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl;
@@ -81,6 +87,37 @@ StaticInstPtr
StaticInst::fetchMicroop(MicroPC micropc)
{
panic("StaticInst::fetchMicroop() called on instruction "
- "that is not microcoded.");
+ "that is not microcoded.");
}
+Addr
+StaticInst::branchTarget(Addr branchPC) const
+{
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not a PC-relative branch.");
+ M5_DUMMY_RETURN;
+}
+
+Addr
+StaticInst::branchTarget(ThreadContext *tc) const
+{
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not an indirect branch.");
+ M5_DUMMY_RETURN;
+}
+
+Request::Flags
+StaticInst::memAccFlags()
+{
+ panic("StaticInst::memAccFlags called on non-memory instruction");
+ return 0;
+}
+
+const string &
+StaticInst::disassemble(Addr pc, const SymbolTable *symtab) const
+{
+ if (!cachedDisassembly)
+ cachedDisassembly = new string(generateDisassembly(pc, symtab));
+
+ return *cachedDisassembly;
+}
diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh
index ceda78d90..cb32f2333 100644
--- a/src/cpu/static_inst.hh
+++ b/src/cpu/static_inst.hh
@@ -42,7 +42,6 @@
#include "base/misc.hh"
#include "base/refcnt.hh"
#include "cpu/op_class.hh"
-#include "cpu/o3/dyn_inst.hh"
#include "sim/faults.hh"
#include "sim/host.hh"
@@ -54,8 +53,11 @@ class ThreadContext;
class DynInst;
class Packet;
-template <class Impl>
-class OzoneDynInst;
+class O3CPUImpl;
+template <class Impl> class BaseO3DynInst;
+typedef BaseO3DynInst<O3CPUImpl> O3DynInst;
+template <class Impl> class OzoneDynInst;
+class InOrderDynInst;
class CheckerCPU;
class FastCPU;
@@ -69,7 +71,27 @@ namespace Trace {
class InstRecord;
}
-typedef uint32_t MicroPC;
+typedef uint16_t MicroPC;
+
+static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1);
+
+static inline MicroPC
+romMicroPC(MicroPC upc)
+{
+ return upc | MicroPCRomBit;
+}
+
+static inline MicroPC
+normalMicroPC(MicroPC upc)
+{
+ return upc & ~MicroPCRomBit;
+}
+
+static inline bool
+isRomMicroPC(MicroPC upc)
+{
+ return MicroPCRomBit & upc;
+}
/**
* Base, ISA-independent static instruction class.
@@ -105,38 +127,39 @@ class StaticInstBase : public RefCounted
/// implement this behavior via the execute() methods.
///
enum Flags {
- IsNop, ///< Is a no-op (no effect at all).
+ IsNop, ///< Is a no-op (no effect at all).
- IsInteger, ///< References integer regs.
- IsFloating, ///< References FP regs.
+ IsInteger, ///< References integer regs.
+ IsFloating, ///< References FP regs.
- IsMemRef, ///< References memory (load, store, or prefetch).
- IsLoad, ///< Reads from memory (load or prefetch).
- IsStore, ///< Writes to memory.
+ IsMemRef, ///< References memory (load, store, or prefetch).
+ IsLoad, ///< Reads from memory (load or prefetch).
+ IsStore, ///< Writes to memory.
IsStoreConditional, ///< Store conditional instruction.
IsIndexed, ///< Accesses memory with an indexed address computation
- IsInstPrefetch, ///< Instruction-cache prefetch.
- IsDataPrefetch, ///< Data-cache prefetch.
+ IsInstPrefetch, ///< Instruction-cache prefetch.
+ IsDataPrefetch, ///< Data-cache prefetch.
IsCopy, ///< Fast Cache block copy
- IsControl, ///< Control transfer instruction.
- IsDirectControl, ///< PC relative control transfer.
- IsIndirectControl, ///< Register indirect control transfer.
- IsCondControl, ///< Conditional control transfer.
- IsUncondControl, ///< Unconditional control transfer.
- IsCall, ///< Subroutine call.
- IsReturn, ///< Subroutine return.
+ IsControl, ///< Control transfer instruction.
+ IsDirectControl, ///< PC relative control transfer.
+ IsIndirectControl, ///< Register indirect control transfer.
+ IsCondControl, ///< Conditional control transfer.
+ IsUncondControl, ///< Unconditional control transfer.
+ IsCall, ///< Subroutine call.
+ IsReturn, ///< Subroutine return.
IsCondDelaySlot,///< Conditional Delay-Slot Instruction
- IsThreadSync, ///< Thread synchronization operation.
+ IsThreadSync, ///< Thread synchronization operation.
- IsSerializing, ///< Serializes pipeline: won't execute until all
+ IsSerializing, ///< Serializes pipeline: won't execute until all
/// older instructions have committed.
IsSerializeBefore,
IsSerializeAfter,
- IsMemBarrier, ///< Is a memory barrier
- IsWriteBarrier, ///< Is a write barrier
+ IsMemBarrier, ///< Is a memory barrier
+ IsWriteBarrier, ///< Is a write barrier
+ IsReadBarrier, ///< Is a read barrier
IsERET, /// <- Causes the IFU to stall (MIPS ISA)
IsNonSpeculative, ///< Should not be executed speculatively
@@ -150,12 +173,12 @@ class StaticInstBase : public RefCounted
//Flags for microcode
IsMacroop, ///< Is a macroop containing microops
- IsMicroop, ///< Is a microop
- IsDelayedCommit, ///< This microop doesn't commit right away
- IsLastMicroop, ///< This microop ends a microop sequence
- IsFirstMicroop, ///< This microop begins a microop sequence
+ IsMicroop, ///< Is a microop
+ IsDelayedCommit, ///< This microop doesn't commit right away
+ IsLastMicroop, ///< This microop ends a microop sequence
+ IsFirstMicroop, ///< This microop begins a microop sequence
//This flag doesn't do anything yet
- IsMicroBranch, ///< This microop branches within the microcode for a macroop
+ IsMicroBranch, ///< This microop branches within the microcode for a macroop
IsDspOp,
NumFlags
@@ -215,26 +238,26 @@ class StaticInstBase : public RefCounted
/// of the individual flags.
//@{
- bool isNop() const { return flags[IsNop]; }
+ bool isNop() const { return flags[IsNop]; }
- bool isMemRef() const { return flags[IsMemRef]; }
- bool isLoad() const { return flags[IsLoad]; }
- bool isStore() const { return flags[IsStore]; }
- bool isStoreConditional() const { return flags[IsStoreConditional]; }
+ bool isMemRef() const { return flags[IsMemRef]; }
+ bool isLoad() const { return flags[IsLoad]; }
+ bool isStore() const { return flags[IsStore]; }
+ bool isStoreConditional() const { return flags[IsStoreConditional]; }
bool isInstPrefetch() const { return flags[IsInstPrefetch]; }
bool isDataPrefetch() const { return flags[IsDataPrefetch]; }
bool isCopy() const { return flags[IsCopy];}
- bool isInteger() const { return flags[IsInteger]; }
- bool isFloating() const { return flags[IsFloating]; }
+ bool isInteger() const { return flags[IsInteger]; }
+ bool isFloating() const { return flags[IsFloating]; }
- bool isControl() const { return flags[IsControl]; }
- bool isCall() const { return flags[IsCall]; }
- bool isReturn() const { return flags[IsReturn]; }
- bool isDirectCtrl() const { return flags[IsDirectControl]; }
+ bool isControl() const { return flags[IsControl]; }
+ bool isCall() const { return flags[IsCall]; }
+ bool isReturn() const { return flags[IsReturn]; }
+ bool isDirectCtrl() const { return flags[IsDirectControl]; }
bool isIndirectCtrl() const { return flags[IsIndirectControl]; }
- bool isCondCtrl() const { return flags[IsCondControl]; }
- bool isUncondCtrl() const { return flags[IsUncondControl]; }
+ bool isCondCtrl() const { return flags[IsCondControl]; }
+ bool isUncondCtrl() const { return flags[IsUncondControl]; }
bool isCondDelaySlot() const { return flags[IsCondDelaySlot]; }
bool isThreadSync() const { return flags[IsThreadSync]; }
@@ -287,8 +310,8 @@ class StaticInst : public StaticInstBase
typedef TheISA::RegIndex RegIndex;
enum {
- MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
- MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
};
@@ -360,12 +383,7 @@ class StaticInst : public StaticInstBase
{ }
public:
-
- virtual ~StaticInst()
- {
- if (cachedDisassembly)
- delete cachedDisassembly;
- }
+ virtual ~StaticInst();
/**
* The execute() signatures are auto-generated by scons based on the
@@ -384,12 +402,7 @@ class StaticInst : public StaticInstBase
* Invalid if not a PC-relative branch (i.e. isDirectCtrl()
* should be true).
*/
- virtual Addr branchTarget(Addr branchPC) const
- {
- panic("StaticInst::branchTarget() called on instruction "
- "that is not a PC-relative branch.");
- M5_DUMMY_RETURN
- }
+ virtual Addr branchTarget(Addr branchPC) const;
/**
* Return the target address for an indirect branch (jump). The
@@ -398,12 +411,7 @@ class StaticInst : public StaticInstBase
* execute the branch in question. Invalid if not an indirect
* branch (i.e. isIndirectCtrl() should be true).
*/
- virtual Addr branchTarget(ThreadContext *tc) const
- {
- panic("StaticInst::branchTarget() called on instruction "
- "that is not an indirect branch.");
- M5_DUMMY_RETURN
- }
+ virtual Addr branchTarget(ThreadContext *tc) const;
/**
* Return true if the instruction is a control transfer, and if so,
@@ -411,6 +419,8 @@ class StaticInst : public StaticInstBase
*/
bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const;
+ virtual Request::Flags memAccFlags();
+
/**
* Return string representation of disassembled instruction.
* The default version of this function will call the internal
@@ -419,14 +429,7 @@ class StaticInst : public StaticInstBase
* should not be cached, this function should be overridden directly.
*/
virtual const std::string &disassemble(Addr pc,
- const SymbolTable *symtab = 0) const
- {
- if (!cachedDisassembly)
- cachedDisassembly =
- new std::string(generateDisassembly(pc, symtab));
-
- return *cachedDisassembly;
- }
+ const SymbolTable *symtab = 0) const;
/// Decoded instruction cache type.
/// For now we're using a generic hash_map; this seems to work
@@ -458,13 +461,13 @@ class StaticInst : public StaticInstBase
/// A cache of decoded instruction objects from addresses.
static AddrDecodeCache addrDecodeCache;
- struct cacheElement {
+ struct cacheElement
+ {
Addr page_addr;
AddrDecodePage *decodePage;
- cacheElement()
- :decodePage(NULL) { }
- } ;
+ cacheElement() : decodePage(NULL) { }
+ };
/// An array of recently decoded instructions.
// might not use an array if there is only two elements
@@ -493,7 +496,7 @@ class StaticInst : public StaticInstBase
/// @retval A pointer to the corresponding StaticInst object.
//This is defined as inlined below.
static StaticInstPtr searchCache(ExtMachInst mach_inst, Addr addr,
- AddrDecodePage * decodePage);
+ AddrDecodePage *decodePage);
};
typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr;
@@ -547,7 +550,8 @@ class AddrDecodePage
public:
/// Constructor
- AddrDecodePage() {
+ AddrDecodePage()
+ {
lowerMask = TheISA::PageBytes - 1;
memset(valid, 0, TheISA::PageBytes);
}
@@ -557,7 +561,8 @@ class AddrDecodePage
/// related to the address
/// @param mach_inst The binary instruction to check
/// @param addr The address containing the instruction
- inline bool decoded(ExtMachInst mach_inst, Addr addr)
+ bool
+ decoded(ExtMachInst mach_inst, Addr addr)
{
return (valid[addr & lowerMask] &&
(instructions[addr & lowerMask]->machInst == mach_inst));
@@ -567,19 +572,22 @@ class AddrDecodePage
/// to check if the instruction is valid.
/// @param addr The address of the instruction.
/// @retval A pointer to the corresponding StaticInst object.
- inline StaticInstPtr getInst(Addr addr)
- { return instructions[addr & lowerMask]; }
+ StaticInstPtr
+ getInst(Addr addr)
+ {
+ return instructions[addr & lowerMask];
+ }
/// Inserts a pointer to a StaticInst object into the list of decoded
/// instructions on the page.
/// @param addr The address of the instruction.
/// @param si A pointer to the corresponding StaticInst object.
- inline void insert(Addr addr, StaticInstPtr &si)
+ void
+ insert(Addr addr, StaticInstPtr &si)
{
instructions[addr & lowerMask] = si;
valid[addr & lowerMask] = true;
}
-
};
@@ -628,7 +636,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr)
}
// creates a new object for a page of decoded instructions
- AddrDecodePage * decodePage = new AddrDecodePage;
+ AddrDecodePage *decodePage = new AddrDecodePage;
addrDecodeCache[page_addr] = decodePage;
updateCache(page_addr, decodePage);
return searchCache(mach_inst, addr, decodePage);
@@ -636,7 +644,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr)
inline StaticInstPtr
StaticInst::searchCache(ExtMachInst mach_inst, Addr addr,
- AddrDecodePage * decodePage)
+ AddrDecodePage *decodePage)
{
DecodeCache::iterator iter = decodeCache.find(mach_inst);
if (iter != decodeCache.end()) {
diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc
index 10c94027d..ab105a435 100644
--- a/src/cpu/thread_context.cc
+++ b/src/cpu/thread_context.cc
@@ -74,8 +74,15 @@ ThreadContext::compare(ThreadContext *one, ThreadContext *two)
if (npc1 != npc2)
panic("NPCs doesn't match, one: %#x, two: %#x", npc1, npc2);
- int id1 = one->readCpuId();
- int id2 = two->readCpuId();
+ int id1 = one->cpuId();
+ int id2 = two->cpuId();
if (id1 != id2)
panic("CPU ids don't match, one: %d, two: %d", id1, id2);
+
+ id1 = one->contextId();
+ id2 = two->contextId();
+ if (id1 != id2)
+ panic("Context ids don't match, one: %d, two: %d", id1, id2);
+
+
}
diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh
index cf51c1637..700f1571e 100644
--- a/src/cpu/thread_context.hh
+++ b/src/cpu/thread_context.hh
@@ -38,7 +38,6 @@
#include "sim/faults.hh"
#include "sim/host.hh"
#include "sim/serialize.hh"
-#include "sim/syscallreturn.hh"
#include "sim/byteswap.hh"
// @todo: Figure out a more architecture independent way to obtain the ITB and
@@ -115,26 +114,30 @@ class ThreadContext
virtual BaseCPU *getCpuPtr() = 0;
- virtual void setCpuId(int id) = 0;
+ virtual int cpuId() = 0;
- virtual int readCpuId() = 0;
+ virtual int threadId() = 0;
+
+ virtual void setThreadId(int id) = 0;
+
+ virtual int contextId() = 0;
+
+ virtual void setContextId(int id) = 0;
virtual TheISA::ITB *getITBPtr() = 0;
virtual TheISA::DTB *getDTBPtr() = 0;
-#if FULL_SYSTEM
virtual System *getSystemPtr() = 0;
+#if FULL_SYSTEM
virtual TheISA::Kernel::Statistics *getKernelStats() = 0;
virtual FunctionalPort *getPhysPort() = 0;
- virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0;
-
- virtual void delVirtPort(VirtualPort *vp) = 0;
+ virtual VirtualPort *getVirtPort() = 0;
- virtual void connectMemPorts() = 0;
+ virtual void connectMemPorts(ThreadContext *tc) = 0;
#else
virtual TranslatingPort *getMemPort() = 0;
@@ -181,8 +184,6 @@ class ThreadContext
virtual void profileSample() = 0;
#endif
- virtual int getThreadNum() = 0;
-
// Also somewhat obnoxious. Really only used for the TLB fault.
// However, may be quite useful in SPARC.
virtual TheISA::MachInst getInst() = 0;
@@ -256,13 +257,6 @@ class ThreadContext
virtual bool misspeculating() = 0;
#if !FULL_SYSTEM
- virtual IntReg getSyscallArg(int i) = 0;
-
- // used to shift args for indirect syscall
- virtual void setSyscallArg(int i, IntReg val) = 0;
-
- virtual void setSyscallReturn(SyscallReturn return_value) = 0;
-
// Same with st cond failures.
virtual Counter readFuncExeInst() = 0;
@@ -274,9 +268,6 @@ class ThreadContext
virtual int exit() { return 1; };
#endif
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val) = 0;
-
/** function to compare two thread contexts (for debugging) */
static void compare(ThreadContext *one, ThreadContext *two);
};
@@ -305,27 +296,31 @@ class ProxyThreadContext : public ThreadContext
BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
- void setCpuId(int id) { actualTC->setCpuId(id); }
+ int cpuId() { return actualTC->cpuId(); }
+
+ int threadId() { return actualTC->threadId(); }
- int readCpuId() { return actualTC->readCpuId(); }
+ void setThreadId(int id) { return actualTC->setThreadId(id); }
+
+ int contextId() { return actualTC->contextId(); }
+
+ void setContextId(int id) { actualTC->setContextId(id); }
TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); }
TheISA::DTB *getDTBPtr() { return actualTC->getDTBPtr(); }
-#if FULL_SYSTEM
System *getSystemPtr() { return actualTC->getSystemPtr(); }
+#if FULL_SYSTEM
TheISA::Kernel::Statistics *getKernelStats()
{ return actualTC->getKernelStats(); }
FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return actualTC->getVirtPort(tc); }
-
- void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); }
+ VirtualPort *getVirtPort() { return actualTC->getVirtPort(); }
- void connectMemPorts() { actualTC->connectMemPorts(); }
+ void connectMemPorts(ThreadContext *tc) { actualTC->connectMemPorts(tc); }
#else
TranslatingPort *getMemPort() { return actualTC->getMemPort(); }
@@ -371,9 +366,6 @@ class ProxyThreadContext : public ThreadContext
void profileClear() { return actualTC->profileClear(); }
void profileSample() { return actualTC->profileSample(); }
#endif
-
- int getThreadNum() { return actualTC->getThreadNum(); }
-
// @todo: Do I need this?
MachInst getInst() { return actualTC->getInst(); }
@@ -433,7 +425,7 @@ class ProxyThreadContext : public ThreadContext
uint64_t readNextMicroPC() { return actualTC->readMicroPC(); }
- void setNextMicroPC(uint64_t val) { actualTC->setMicroPC(val); }
+ void setNextMicroPC(uint64_t val) { actualTC->setNextMicroPC(val); }
MiscReg readMiscRegNoEffect(int misc_reg)
{ return actualTC->readMiscRegNoEffect(misc_reg); }
@@ -457,26 +449,11 @@ class ProxyThreadContext : public ThreadContext
bool misspeculating() { return actualTC->misspeculating(); }
#if !FULL_SYSTEM
- IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, IntReg val)
- { actualTC->setSyscallArg(i, val); }
-
- void setSyscallReturn(SyscallReturn return_value)
- { actualTC->setSyscallReturn(return_value); }
-
void syscall(int64_t callnum)
{ actualTC->syscall(callnum); }
Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
#endif
-
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- actualTC->changeRegFileContext(param, val);
- }
};
#endif
diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc
index be8f822f2..b0e719ddf 100644
--- a/src/cpu/thread_state.cc
+++ b/src/cpu/thread_state.cc
@@ -43,15 +43,15 @@
#endif
#if FULL_SYSTEM
-ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid)
- : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0),
+ThreadState::ThreadState(BaseCPU *cpu, int _tid)
+ : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0),
profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL),
- physPort(NULL), virtPort(NULL),
+ kernelStats(NULL), physPort(NULL), virtPort(NULL),
microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0)
#else
-ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process,
+ThreadState::ThreadState(BaseCPU *cpu, int _tid, Process *_process,
short _asid)
- : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0),
+ : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0),
port(NULL), process(_process), asid(_asid),
microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0)
#endif
@@ -105,7 +105,7 @@ ThreadState::unserialize(Checkpoint *cp, const std::string &section)
Tick quiesceEndTick;
UNSERIALIZE_SCALAR(quiesceEndTick);
if (quiesceEndTick)
- quiesceEvent->schedule(quiesceEndTick);
+ baseCpu->schedule(quiesceEvent, quiesceEndTick);
if (kernelStats)
kernelStats->unserialize(cp, section);
#endif
@@ -113,10 +113,10 @@ ThreadState::unserialize(Checkpoint *cp, const std::string &section)
#if FULL_SYSTEM
void
-ThreadState::connectMemPorts()
+ThreadState::connectMemPorts(ThreadContext *tc)
{
connectPhysPort();
- connectVirtPort();
+ connectVirtPort(tc);
}
void
@@ -129,12 +129,12 @@ ThreadState::connectPhysPort()
physPort->removeConn();
else
physPort = new FunctionalPort(csprintf("%s-%d-funcport",
- baseCpu->name(), tid));
+ baseCpu->name(), _threadId));
connectToMemFunc(physPort);
}
void
-ThreadState::connectVirtPort()
+ThreadState::connectVirtPort(ThreadContext *tc)
{
// @todo: For now this disregards any older port that may have
// already existed. Fix this memory leak once the bus port IDs
@@ -143,7 +143,7 @@ ThreadState::connectVirtPort()
virtPort->removeConn();
else
virtPort = new VirtualPort(csprintf("%s-%d-vport",
- baseCpu->name(), tid));
+ baseCpu->name(), _threadId), tc);
connectToMemFunc(virtPort);
}
@@ -169,7 +169,7 @@ ThreadState::getMemPort()
return port;
/* Use this port to for syscall emulation writes to memory. */
- port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), tid),
+ port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), _threadId),
process, TranslatingPort::NextPage);
connectToMemFunc(port);
diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh
index 4f878db1f..99f0c2a87 100644
--- a/src/cpu/thread_state.hh
+++ b/src/cpu/thread_state.hh
@@ -34,6 +34,7 @@
#include "arch/types.hh"
#include "cpu/profile.hh"
#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
#if !FULL_SYSTEM
#include "mem/mem_object.hh"
@@ -51,7 +52,6 @@ namespace TheISA {
};
#endif
-class BaseCPU;
class Checkpoint;
class Port;
class TranslatingPort;
@@ -66,9 +66,9 @@ struct ThreadState {
typedef ThreadContext::Status Status;
#if FULL_SYSTEM
- ThreadState(BaseCPU *cpu, int _cpuId, int _tid);
+ ThreadState(BaseCPU *cpu, int _tid);
#else
- ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process,
+ ThreadState(BaseCPU *cpu, int _tid, Process *_process,
short _asid);
#endif
@@ -78,24 +78,26 @@ struct ThreadState {
void unserialize(Checkpoint *cp, const std::string &section);
- void setCpuId(int id) { cpuId = id; }
+ int cpuId() { return baseCpu->cpuId(); }
- int readCpuId() { return cpuId; }
+ int contextId() { return _contextId; }
- void setTid(int id) { tid = id; }
+ void setContextId(int id) { _contextId = id; }
- int readTid() { return tid; }
+ void setThreadId(int id) { _threadId = id; }
+
+ int threadId() { return _threadId; }
Tick readLastActivate() { return lastActivate; }
Tick readLastSuspend() { return lastSuspend; }
#if FULL_SYSTEM
- void connectMemPorts();
+ void connectMemPorts(ThreadContext *tc);
void connectPhysPort();
- void connectVirtPort();
+ void connectVirtPort(ThreadContext *tc);
void dumpFuncProfile();
@@ -111,9 +113,7 @@ struct ThreadState {
void setPhysPort(FunctionalPort *port) { physPort = port; }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; }
-
- void setVirtPort(VirtualPort *port) { virtPort = port; }
+ VirtualPort *getVirtPort() { return virtPort; }
#else
Process *getProcessPtr() { return process; }
@@ -155,9 +155,9 @@ struct ThreadState {
/** Number of instructions committed. */
Counter numInst;
/** Stat for number instructions committed. */
- Stats::Scalar<> numInsts;
+ Stats::Scalar numInsts;
/** Stat for number of memory references. */
- Stats::Scalar<> numMemRefs;
+ Stats::Scalar numMemRefs;
/** Number of simulated loads, used for tracking events based on
* the number of loads committed.
@@ -173,12 +173,11 @@ struct ThreadState {
// Pointer to the base CPU.
BaseCPU *baseCpu;
- // ID of this context w.r.t. the System or Process object to which
- // it belongs. For full-system mode, this is the system CPU ID.
- int cpuId;
+ // system wide HW context id
+ int _contextId;
// Index of hardware thread context on the CPU that this represents.
- int tid;
+ int _threadId;
public:
/** Last time activate was called on this thread. */
@@ -201,7 +200,7 @@ struct ThreadState {
FunctionalPort *physPort;
/** A functional port, outgoing only, for functional accesse to virtual
- * addresses. That doen't require execution context information */
+ * addresses. */
VirtualPort *virtPort;
#else
TranslatingPort *port;