Adding gem5 source to svn.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1819 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
233
simulators/gem5/src/cpu/BaseCPU.py
Normal file
233
simulators/gem5/src/cpu/BaseCPU.py
Normal file
@ -0,0 +1,233 @@
|
||||
# Copyright (c) 2012 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
# not be construed as granting a license to any other intellectual
|
||||
# property including but not limited to intellectual property relating
|
||||
# to a hardware implementation of the functionality of the software
|
||||
# licensed hereunder. You may use the software subject to the license
|
||||
# terms below provided that you ensure that this notice is replicated
|
||||
# unmodified and in its entirety in all distributions of the software,
|
||||
# modified or unmodified, in source code or in binary form.
|
||||
#
|
||||
# Copyright (c) 2005-2008 The Regents of The University of Michigan
|
||||
# Copyright (c) 2011 Regents of the University of California
|
||||
# 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
|
||||
# Rick Strong
|
||||
# Andreas Hansson
|
||||
|
||||
import sys
|
||||
|
||||
from m5.defines import buildEnv
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
|
||||
from Bus import CoherentBus
|
||||
from InstTracer import InstTracer
|
||||
from ExeTracer import ExeTracer
|
||||
from MemObject import MemObject
|
||||
|
||||
default_tracer = ExeTracer()
|
||||
|
||||
if buildEnv['TARGET_ISA'] == 'alpha':
|
||||
from AlphaTLB import AlphaDTB, AlphaITB
|
||||
from AlphaInterrupts import AlphaInterrupts
|
||||
elif buildEnv['TARGET_ISA'] == 'sparc':
|
||||
from SparcTLB import SparcTLB
|
||||
from SparcInterrupts import SparcInterrupts
|
||||
elif buildEnv['TARGET_ISA'] == 'x86':
|
||||
from X86TLB import X86TLB
|
||||
from X86LocalApic import X86LocalApic
|
||||
elif buildEnv['TARGET_ISA'] == 'mips':
|
||||
from MipsTLB import MipsTLB
|
||||
from MipsInterrupts import MipsInterrupts
|
||||
elif buildEnv['TARGET_ISA'] == 'arm':
|
||||
from ArmTLB import ArmTLB
|
||||
from ArmInterrupts import ArmInterrupts
|
||||
elif buildEnv['TARGET_ISA'] == 'power':
|
||||
from PowerTLB import PowerTLB
|
||||
from PowerInterrupts import PowerInterrupts
|
||||
|
||||
class BaseCPU(MemObject):
|
||||
type = 'BaseCPU'
|
||||
abstract = True
|
||||
|
||||
system = Param.System(Parent.any, "system object")
|
||||
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")
|
||||
|
||||
profile = Param.Latency('0ns', "trace the kernel stack")
|
||||
do_quiesce = Param.Bool(True, "enable quiesce instructions")
|
||||
|
||||
workload = VectorParam.Process([], "processes to run")
|
||||
|
||||
if buildEnv['TARGET_ISA'] == 'sparc':
|
||||
dtb = Param.SparcTLB(SparcTLB(), "Data TLB")
|
||||
itb = Param.SparcTLB(SparcTLB(), "Instruction TLB")
|
||||
interrupts = Param.SparcInterrupts(
|
||||
NULL, "Interrupt Controller")
|
||||
elif buildEnv['TARGET_ISA'] == 'alpha':
|
||||
dtb = Param.AlphaTLB(AlphaDTB(), "Data TLB")
|
||||
itb = Param.AlphaTLB(AlphaITB(), "Instruction TLB")
|
||||
interrupts = Param.AlphaInterrupts(
|
||||
NULL, "Interrupt Controller")
|
||||
elif buildEnv['TARGET_ISA'] == 'x86':
|
||||
dtb = Param.X86TLB(X86TLB(), "Data TLB")
|
||||
itb = Param.X86TLB(X86TLB(), "Instruction TLB")
|
||||
interrupts = Param.X86LocalApic(NULL, "Interrupt Controller")
|
||||
elif buildEnv['TARGET_ISA'] == 'mips':
|
||||
dtb = Param.MipsTLB(MipsTLB(), "Data TLB")
|
||||
itb = Param.MipsTLB(MipsTLB(), "Instruction TLB")
|
||||
interrupts = Param.MipsInterrupts(
|
||||
NULL, "Interrupt Controller")
|
||||
elif buildEnv['TARGET_ISA'] == 'arm':
|
||||
dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
|
||||
itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
|
||||
interrupts = Param.ArmInterrupts(
|
||||
NULL, "Interrupt Controller")
|
||||
elif buildEnv['TARGET_ISA'] == 'power':
|
||||
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
|
||||
dtb = Param.PowerTLB(PowerTLB(), "Data TLB")
|
||||
itb = Param.PowerTLB(PowerTLB(), "Instruction TLB")
|
||||
interrupts = Param.PowerInterrupts(
|
||||
NULL, "Interrupt Controller")
|
||||
else:
|
||||
print "Don't know what TLB to use for ISA %s" % \
|
||||
buildEnv['TARGET_ISA']
|
||||
sys.exit(1)
|
||||
|
||||
max_insts_all_threads = Param.Counter(0,
|
||||
"terminate when all threads have reached this inst count")
|
||||
max_insts_any_thread = Param.Counter(0,
|
||||
"terminate when any thread reaches this inst count")
|
||||
max_loads_all_threads = Param.Counter(0,
|
||||
"terminate when all threads have reached this load count")
|
||||
max_loads_any_thread = Param.Counter(0,
|
||||
"terminate when any thread reaches this load count")
|
||||
progress_interval = Param.Tick(0,
|
||||
"interval to print out the progress message")
|
||||
|
||||
defer_registration = Param.Bool(False,
|
||||
"defer registration with system (for sampling)")
|
||||
|
||||
clock = Param.Clock('1t', "clock speed")
|
||||
phase = Param.Latency('0ns', "clock phase")
|
||||
|
||||
tracer = Param.InstTracer(default_tracer, "Instruction tracer")
|
||||
|
||||
icache_port = MasterPort("Instruction Port")
|
||||
dcache_port = MasterPort("Data Port")
|
||||
_cached_ports = ['icache_port', 'dcache_port']
|
||||
|
||||
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
|
||||
_cached_ports += ["itb.walker.port", "dtb.walker.port"]
|
||||
|
||||
_uncached_slave_ports = []
|
||||
_uncached_master_ports = []
|
||||
if buildEnv['TARGET_ISA'] == 'x86':
|
||||
_uncached_slave_ports += ["interrupts.pio", "interrupts.int_slave"]
|
||||
_uncached_master_ports += ["interrupts.int_master"]
|
||||
|
||||
def createInterruptController(self):
|
||||
if buildEnv['TARGET_ISA'] == 'sparc':
|
||||
self.interrupts = SparcInterrupts()
|
||||
elif buildEnv['TARGET_ISA'] == 'alpha':
|
||||
self.interrupts = AlphaInterrupts()
|
||||
elif buildEnv['TARGET_ISA'] == 'x86':
|
||||
_localApic = X86LocalApic(pio_addr=0x2000000000000000)
|
||||
self.interrupts = _localApic
|
||||
elif buildEnv['TARGET_ISA'] == 'mips':
|
||||
self.interrupts = MipsInterrupts()
|
||||
elif buildEnv['TARGET_ISA'] == 'arm':
|
||||
self.interrupts = ArmInterrupts()
|
||||
elif buildEnv['TARGET_ISA'] == 'power':
|
||||
self.interrupts = PowerInterrupts()
|
||||
else:
|
||||
print "Don't know what Interrupt Controller to use for ISA %s" % \
|
||||
buildEnv['TARGET_ISA']
|
||||
sys.exit(1)
|
||||
|
||||
def connectCachedPorts(self, bus):
|
||||
for p in self._cached_ports:
|
||||
exec('self.%s = bus.slave' % p)
|
||||
|
||||
def connectUncachedPorts(self, bus):
|
||||
for p in self._uncached_slave_ports:
|
||||
exec('self.%s = bus.master' % p)
|
||||
for p in self._uncached_master_ports:
|
||||
exec('self.%s = bus.slave' % p)
|
||||
|
||||
def connectAllPorts(self, cached_bus, uncached_bus = None):
|
||||
self.connectCachedPorts(cached_bus)
|
||||
if not uncached_bus:
|
||||
uncached_bus = cached_bus
|
||||
self.connectUncachedPorts(uncached_bus)
|
||||
|
||||
def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None):
|
||||
self.icache = ic
|
||||
self.dcache = dc
|
||||
self.icache_port = ic.cpu_side
|
||||
self.dcache_port = dc.cpu_side
|
||||
self._cached_ports = ['icache.mem_side', 'dcache.mem_side']
|
||||
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
|
||||
if iwc and dwc:
|
||||
self.itb_walker_cache = iwc
|
||||
self.dtb_walker_cache = dwc
|
||||
self.itb.walker.port = iwc.cpu_side
|
||||
self.dtb.walker.port = dwc.cpu_side
|
||||
self._cached_ports += ["itb_walker_cache.mem_side", \
|
||||
"dtb_walker_cache.mem_side"]
|
||||
else:
|
||||
self._cached_ports += ["itb.walker.port", "dtb.walker.port"]
|
||||
|
||||
# Checker doesn't need its own tlb caches because it does
|
||||
# functional accesses only
|
||||
if self.checker != NULL:
|
||||
self._cached_ports += ["checker.itb.walker.port", \
|
||||
"checker.dtb.walker.port"]
|
||||
|
||||
def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
|
||||
self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
|
||||
self.toL2Bus = CoherentBus()
|
||||
self.connectCachedPorts(self.toL2Bus)
|
||||
self.l2cache = l2c
|
||||
self.toL2Bus.master = self.l2cache.cpu_side
|
||||
self._cached_ports = ['l2cache.mem_side']
|
||||
|
||||
def addCheckerCpu(self):
|
||||
pass
|
||||
41
simulators/gem5/src/cpu/CheckerCPU.py
Normal file
41
simulators/gem5/src/cpu/CheckerCPU.py
Normal file
@ -0,0 +1,41 @@
|
||||
# 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 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(True,
|
||||
"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")
|
||||
42
simulators/gem5/src/cpu/DummyChecker.py
Normal file
42
simulators/gem5/src/cpu/DummyChecker.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2010-2011 ARM Limited
|
||||
# All rights reserved
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
# not be construed as granting a license to any other intellectual
|
||||
# property including but not limited to intellectual property relating
|
||||
# to a hardware implementation of the functionality of the software
|
||||
# licensed hereunder. You may use the software subject to the license
|
||||
# terms below provided that you ensure that this notice is replicated
|
||||
# unmodified and in its entirety in all distributions of the software,
|
||||
# modified or unmodified, in source code or in binary form.
|
||||
#
|
||||
# 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: Geoffrey Blake
|
||||
|
||||
from m5.params import *
|
||||
from BaseCPU import BaseCPU
|
||||
|
||||
class DummyChecker(BaseCPU):
|
||||
type = 'DummyChecker'
|
||||
35
simulators/gem5/src/cpu/ExeTracer.py
Normal file
35
simulators/gem5/src/cpu/ExeTracer.py
Normal file
@ -0,0 +1,35 @@
|
||||
# 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: Gabe Black
|
||||
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from InstTracer import InstTracer
|
||||
|
||||
class ExeTracer(InstTracer):
|
||||
type = 'ExeTracer'
|
||||
cxx_class = 'Trace::ExeTracer'
|
||||
63
simulators/gem5/src/cpu/FuncUnit.py
Normal file
63
simulators/gem5/src/cpu/FuncUnit.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Copyright (c) 2010 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
# not be construed as granting a license to any other intellectual
|
||||
# property including but not limited to intellectual property relating
|
||||
# to a hardware implementation of the functionality of the software
|
||||
# licensed hereunder. You may use the software subject to the license
|
||||
# terms below provided that you ensure that this notice is replicated
|
||||
# unmodified and in its entirety in all distributions of the software,
|
||||
# modified or unmodified, in source code or in binary form.
|
||||
#
|
||||
# Copyright (c) 2006-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: Kevin Lim
|
||||
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
|
||||
class OpClass(Enum):
|
||||
vals = ['No_OpClass', 'IntAlu', 'IntMult', 'IntDiv', 'FloatAdd',
|
||||
'FloatCmp', 'FloatCvt', 'FloatMult', 'FloatDiv', 'FloatSqrt',
|
||||
'SimdAdd', 'SimdAddAcc', 'SimdAlu', 'SimdCmp', 'SimdCvt',
|
||||
'SimdMisc', 'SimdMult', 'SimdMultAcc', 'SimdShift', 'SimdShiftAcc',
|
||||
'SimdSqrt', 'SimdFloatAdd', 'SimdFloatAlu', 'SimdFloatCmp',
|
||||
'SimdFloatCvt', 'SimdFloatDiv', 'SimdFloatMisc', 'SimdFloatMult',
|
||||
'SimdFloatMultAcc', 'SimdFloatSqrt',
|
||||
'MemRead', 'MemWrite', 'IprAccess', 'InstPrefetch']
|
||||
|
||||
class OpDesc(SimObject):
|
||||
type = 'OpDesc'
|
||||
issueLat = Param.Int(1, "cycles until another can be issued")
|
||||
opClass = Param.OpClass("type of operation")
|
||||
opLat = Param.Int(1, "cycles until result is available")
|
||||
|
||||
class FUDesc(SimObject):
|
||||
type = 'FUDesc'
|
||||
count = Param.Int("number of these FU's available")
|
||||
opList = VectorParam.OpDesc("operation classes for this FU type")
|
||||
35
simulators/gem5/src/cpu/IntelTrace.py
Normal file
35
simulators/gem5/src/cpu/IntelTrace.py
Normal file
@ -0,0 +1,35 @@
|
||||
# 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: Gabe Black
|
||||
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from InstTracer import InstTracer
|
||||
|
||||
class IntelTrace(InstTracer):
|
||||
type = 'IntelTrace'
|
||||
cxx_class = 'Trace::IntelTrace'
|
||||
34
simulators/gem5/src/cpu/IntrControl.py
Normal file
34
simulators/gem5/src/cpu/IntrControl.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2005-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.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
class IntrControl(SimObject):
|
||||
type = 'IntrControl'
|
||||
sys = Param.System(Parent.any, "the system we are part of")
|
||||
35
simulators/gem5/src/cpu/LegionTrace.py
Normal file
35
simulators/gem5/src/cpu/LegionTrace.py
Normal file
@ -0,0 +1,35 @@
|
||||
# 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: Gabe Black
|
||||
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from InstTracer import InstTracer
|
||||
|
||||
class LegionTrace(InstTracer):
|
||||
type = 'LegionTrace'
|
||||
cxx_class = 'Trace::LegionTrace'
|
||||
36
simulators/gem5/src/cpu/NativeTrace.py
Normal file
36
simulators/gem5/src/cpu/NativeTrace.py
Normal file
@ -0,0 +1,36 @@
|
||||
# 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: Gabe Black
|
||||
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from ExeTracer import ExeTracer
|
||||
|
||||
class NativeTrace(ExeTracer):
|
||||
abstract = True
|
||||
type = 'NativeTrace'
|
||||
cxx_class = 'Trace::NativeTrace'
|
||||
171
simulators/gem5/src/cpu/SConscript
Normal file
171
simulators/gem5/src/cpu/SConscript
Normal file
@ -0,0 +1,171 @@
|
||||
# -*- mode:python -*-
|
||||
|
||||
# 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: Steve Reinhardt
|
||||
|
||||
Import('*')
|
||||
|
||||
if env['TARGET_ISA'] == 'no':
|
||||
Return()
|
||||
|
||||
#################################################################
|
||||
#
|
||||
# Generate StaticInst execute() method signatures.
|
||||
#
|
||||
# There must be one signature for each CPU model compiled in.
|
||||
# Since the set of compiled-in models is flexible, we generate a
|
||||
# header containing the appropriate set of signatures on the fly.
|
||||
#
|
||||
#################################################################
|
||||
|
||||
# Template for execute() signature.
|
||||
exec_sig_template = '''
|
||||
virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0;
|
||||
virtual Fault eaComp(%(type)s *xc, Trace::InstRecord *traceData) const
|
||||
{ panic("eaComp not defined!"); M5_DUMMY_RETURN };
|
||||
virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const
|
||||
{ panic("initiateAcc not defined!"); M5_DUMMY_RETURN };
|
||||
virtual Fault completeAcc(Packet *pkt, %(type)s *xc,
|
||||
Trace::InstRecord *traceData) const
|
||||
{ panic("completeAcc not defined!"); M5_DUMMY_RETURN };
|
||||
'''
|
||||
|
||||
mem_ini_sig_template = '''
|
||||
virtual Fault eaComp(%(type)s *xc, Trace::InstRecord *traceData) const
|
||||
{ panic("eaComp not defined!"); M5_DUMMY_RETURN };
|
||||
virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); M5_DUMMY_RETURN };
|
||||
'''
|
||||
|
||||
mem_comp_sig_template = '''
|
||||
virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; M5_DUMMY_RETURN };
|
||||
'''
|
||||
|
||||
# Generate a temporary CPU list, including the CheckerCPU if
|
||||
# it's enabled. This isn't used for anything else other than StaticInst
|
||||
# headers.
|
||||
temp_cpu_list = env['CPU_MODELS'][:]
|
||||
temp_cpu_list.append('CheckerCPU')
|
||||
SimObject('CheckerCPU.py')
|
||||
|
||||
# Generate header.
|
||||
def gen_cpu_exec_signatures(target, source, env):
|
||||
f = open(str(target[0]), 'w')
|
||||
print >> f, '''
|
||||
#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__
|
||||
#define __CPU_STATIC_INST_EXEC_SIGS_HH__
|
||||
'''
|
||||
for cpu in temp_cpu_list:
|
||||
xc_type = CpuModel.dict[cpu].strings['CPU_exec_context']
|
||||
print >> f, exec_sig_template % { 'type' : xc_type }
|
||||
print >> f, '''
|
||||
#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__
|
||||
'''
|
||||
|
||||
# Generate string that gets printed when header is rebuilt
|
||||
def gen_sigs_string(target, source, env):
|
||||
return " [GENERATE] static_inst_exec_sigs.hh: " \
|
||||
+ ', '.join(temp_cpu_list)
|
||||
|
||||
# Add command to generate header to environment.
|
||||
env.Command('static_inst_exec_sigs.hh', (),
|
||||
Action(gen_cpu_exec_signatures, gen_sigs_string,
|
||||
varlist = temp_cpu_list))
|
||||
|
||||
env.Depends('static_inst_exec_sigs.hh', Value(env['CPU_MODELS']))
|
||||
|
||||
SimObject('BaseCPU.py')
|
||||
SimObject('FuncUnit.py')
|
||||
SimObject('ExeTracer.py')
|
||||
SimObject('IntelTrace.py')
|
||||
SimObject('IntrControl.py')
|
||||
SimObject('NativeTrace.py')
|
||||
|
||||
Source('activity.cc')
|
||||
Source('base.cc')
|
||||
Source('cpuevent.cc')
|
||||
Source('exetrace.cc')
|
||||
Source('func_unit.cc')
|
||||
Source('inteltrace.cc')
|
||||
Source('intr_control.cc')
|
||||
Source('nativetrace.cc')
|
||||
Source('pc_event.cc')
|
||||
Source('profile.cc')
|
||||
Source('quiesce_event.cc')
|
||||
Source('static_inst.cc')
|
||||
Source('simple_thread.cc')
|
||||
Source('thread_context.cc')
|
||||
Source('thread_state.cc')
|
||||
|
||||
if env['TARGET_ISA'] == 'sparc':
|
||||
SimObject('LegionTrace.py')
|
||||
Source('legiontrace.cc')
|
||||
|
||||
SimObject('DummyChecker.py')
|
||||
Source('checker/cpu.cc')
|
||||
Source('dummy_checker_builder.cc')
|
||||
DebugFlag('Checker')
|
||||
|
||||
DebugFlag('Activity')
|
||||
DebugFlag('Commit')
|
||||
DebugFlag('Context')
|
||||
DebugFlag('Decode')
|
||||
DebugFlag('DynInst')
|
||||
DebugFlag('ExecEnable')
|
||||
DebugFlag('ExecCPSeq')
|
||||
DebugFlag('ExecEffAddr')
|
||||
DebugFlag('ExecFaulting', 'Trace faulting instructions')
|
||||
DebugFlag('ExecFetchSeq')
|
||||
DebugFlag('ExecOpClass')
|
||||
DebugFlag('ExecRegDelta')
|
||||
DebugFlag('ExecResult')
|
||||
DebugFlag('ExecSpeculative')
|
||||
DebugFlag('ExecSymbol')
|
||||
DebugFlag('ExecThread')
|
||||
DebugFlag('ExecTicks')
|
||||
DebugFlag('ExecMicro')
|
||||
DebugFlag('ExecMacro')
|
||||
DebugFlag('ExecUser')
|
||||
DebugFlag('ExecKernel')
|
||||
DebugFlag('ExecAsid')
|
||||
DebugFlag('Fetch')
|
||||
DebugFlag('IntrControl')
|
||||
DebugFlag('O3PipeView')
|
||||
DebugFlag('PCEvent')
|
||||
DebugFlag('Quiesce')
|
||||
|
||||
CompoundFlag('ExecAll', [ 'ExecEnable', 'ExecCPSeq', 'ExecEffAddr',
|
||||
'ExecFaulting', 'ExecFetchSeq', 'ExecOpClass', 'ExecRegDelta',
|
||||
'ExecResult', 'ExecSpeculative', 'ExecSymbol', 'ExecThread',
|
||||
'ExecTicks', 'ExecMicro', 'ExecMacro', 'ExecUser', 'ExecKernel',
|
||||
'ExecAsid' ])
|
||||
CompoundFlag('Exec', [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', 'ExecThread',
|
||||
'ExecEffAddr', 'ExecResult', 'ExecSymbol', 'ExecMicro', 'ExecFaulting',
|
||||
'ExecUser', 'ExecKernel' ])
|
||||
CompoundFlag('ExecNoTicks', [ 'ExecEnable', 'ExecOpClass', 'ExecThread',
|
||||
'ExecEffAddr', 'ExecResult', 'ExecMicro', 'ExecFaulting',
|
||||
'ExecUser', 'ExecKernel' ])
|
||||
163
simulators/gem5/src/cpu/activity.cc
Normal file
163
simulators/gem5/src/cpu/activity.cc
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cpu/activity.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "debug/Activity.hh"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::activity()
|
||||
{
|
||||
// If we've already recorded activity for this cycle, we don't
|
||||
// want to increment the count any more.
|
||||
if (activityBuffer[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
activityBuffer[0] = true;
|
||||
|
||||
++activityCount;
|
||||
|
||||
DPRINTF(Activity, "Activity: %i\n", activityCount);
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::advance()
|
||||
{
|
||||
// If there's a 1 in the slot that is about to be erased once the
|
||||
// time buffer advances, then decrement the activityCount.
|
||||
if (activityBuffer[-longestLatency]) {
|
||||
--activityCount;
|
||||
|
||||
assert(activityCount >= 0);
|
||||
|
||||
DPRINTF(Activity, "Activity: %i\n", activityCount);
|
||||
|
||||
if (activityCount == 0) {
|
||||
DPRINTF(Activity, "No activity left!\n");
|
||||
}
|
||||
}
|
||||
|
||||
activityBuffer.advance();
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::activateStage(const int idx)
|
||||
{
|
||||
// Increment the activity count if this stage wasn't already active.
|
||||
if (!stageActive[idx]) {
|
||||
++activityCount;
|
||||
|
||||
stageActive[idx] = true;
|
||||
|
||||
DPRINTF(Activity, "Activity: %i\n", activityCount);
|
||||
} else {
|
||||
DPRINTF(Activity, "Stage %i already active.\n", idx);
|
||||
}
|
||||
|
||||
// assert(activityCount < longestLatency + numStages + 1);
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::deactivateStage(const int idx)
|
||||
{
|
||||
// Decrement the activity count if this stage was active.
|
||||
if (stageActive[idx]) {
|
||||
--activityCount;
|
||||
|
||||
stageActive[idx] = false;
|
||||
|
||||
DPRINTF(Activity, "Activity: %i\n", activityCount);
|
||||
} else {
|
||||
DPRINTF(Activity, "Stage %i already inactive.\n", idx);
|
||||
}
|
||||
|
||||
assert(activityCount >= 0);
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::reset()
|
||||
{
|
||||
activityCount = 0;
|
||||
std::memset(stageActive, 0, numStages);
|
||||
for (int i = 0; i < longestLatency + 1; ++i)
|
||||
activityBuffer.advance();
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::dump()
|
||||
{
|
||||
for (int i = 0; i <= longestLatency; ++i) {
|
||||
cprintf("[Idx:%i %i] ", i, activityBuffer[-i]);
|
||||
}
|
||||
|
||||
cprintf("\n");
|
||||
|
||||
for (int i = 0; i < numStages; ++i) {
|
||||
cprintf("[Stage:%i %i]\n", i, stageActive[i]);
|
||||
}
|
||||
|
||||
cprintf("\n");
|
||||
|
||||
cprintf("Activity count: %i\n", activityCount);
|
||||
}
|
||||
|
||||
void
|
||||
ActivityRecorder::validate()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i <= longestLatency; ++i) {
|
||||
if (activityBuffer[-i]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStages; ++i) {
|
||||
if (stageActive[i]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(count == activityCount);
|
||||
}
|
||||
132
simulators/gem5/src/cpu/activity.hh
Normal file
132
simulators/gem5/src/cpu/activity.hh
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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_ACTIVITY_HH__
|
||||
#define __CPU_ACTIVITY_HH__
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
|
||||
/**
|
||||
* ActivityRecorder helper class that informs the CPU if it can switch
|
||||
* over to being idle or not. It works by having a time buffer as
|
||||
* long as any time buffer in the CPU, and the CPU and all of its
|
||||
* stages inform the ActivityRecorder when they write to any time
|
||||
* buffer. The ActivityRecorder marks a 1 in the "0" slot of the time
|
||||
* buffer any time a stage writes to a time buffer, and it advances
|
||||
* its time buffer at the same time as all other stages. The
|
||||
* ActivityRecorder also records if a stage has activity to do next
|
||||
* cycle. The recorder keeps a count of these two. Thus any time the
|
||||
* count is non-zero, there is either communication still in flight,
|
||||
* or activity that still must be done, meaning that the CPU can not
|
||||
* idle. If count is zero, then the CPU can safely idle as it has no
|
||||
* more outstanding work to do.
|
||||
*/
|
||||
class ActivityRecorder
|
||||
{
|
||||
public:
|
||||
ActivityRecorder(const std::string &name, int num_stages,
|
||||
int longest_latency, int count);
|
||||
|
||||
/** Records that there is activity this cycle. */
|
||||
void activity();
|
||||
|
||||
/** Advances the activity buffer, decrementing the activityCount
|
||||
* if active communication just left the time buffer, and
|
||||
* determining if there is no activity.
|
||||
*/
|
||||
void advance();
|
||||
|
||||
/** Marks a stage as active. */
|
||||
void activateStage(const int idx);
|
||||
|
||||
/** Deactivates a stage. */
|
||||
void deactivateStage(const int idx);
|
||||
|
||||
/** Returns how many things are active within the recorder. */
|
||||
int getActivityCount() { return activityCount; }
|
||||
|
||||
/** Sets the count to a starting value. Can be used to disable
|
||||
* the idling option.
|
||||
*/
|
||||
void setActivityCount(int count)
|
||||
{ activityCount = count; }
|
||||
|
||||
/** Returns if the CPU should be active. */
|
||||
bool active() { return activityCount; }
|
||||
|
||||
/** Clears the time buffer and the activity count. */
|
||||
void reset();
|
||||
|
||||
/** Debug function to dump the contents of the time buffer. */
|
||||
void dump();
|
||||
|
||||
/** Debug function to ensure that the activity count matches the
|
||||
* contents of the time buffer.
|
||||
*/
|
||||
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,
|
||||
* the activity buffer should also be written to. The
|
||||
* activityBuffer is advanced along with all the other time
|
||||
* buffers, so it should have a 1 somewhere in it only if there
|
||||
* is active communication in a time buffer.
|
||||
*/
|
||||
TimeBuffer<bool> activityBuffer;
|
||||
|
||||
/** Longest latency time buffer in the CPU. */
|
||||
int longestLatency;
|
||||
|
||||
/** Tracks how many stages and cycles of time buffer have
|
||||
* activity. Stages increment this count when they switch to
|
||||
* active, and decrement it when they switch to
|
||||
* inactive. Whenever a cycle that previously had no information
|
||||
* is written in the time buffer, this is incremented. When a
|
||||
* cycle that had information exits the time buffer due to age,
|
||||
* this count is decremented. When the count is 0, there is no
|
||||
* activity in the CPU, and it can be descheduled.
|
||||
*/
|
||||
int activityCount;
|
||||
|
||||
/** Number of stages that can be marked as active or inactive. */
|
||||
int numStages;
|
||||
|
||||
/** Records which stages are active/inactive. */
|
||||
bool *stageActive;
|
||||
};
|
||||
|
||||
#endif // __CPU_ACTIVITY_HH__
|
||||
553
simulators/gem5/src/cpu/base.cc
Normal file
553
simulators/gem5/src/cpu/base.cc
Normal file
@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||
* Copyright (c) 2011 Regents of the University of California
|
||||
* 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: Steve Reinhardt
|
||||
* Nathan Binkert
|
||||
* Rick Strong
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "arch/tlb.hh"
|
||||
#include "base/loader/symtab.hh"
|
||||
#include "base/cprintf.hh"
|
||||
#include "base/misc.hh"
|
||||
#include "base/output.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/cpuevent.hh"
|
||||
#include "cpu/profile.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/SyscallVerbose.hh"
|
||||
#include "params/BaseCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/sim_events.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
// Hack
|
||||
#include "sim/stat_control.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<BaseCPU *> BaseCPU::cpuList;
|
||||
|
||||
// This variable reflects the max number of threads in any CPU. Be
|
||||
// careful to only use it once all the CPUs that you care about have
|
||||
// been initialized
|
||||
int maxThreadsPerCPU = 1;
|
||||
|
||||
CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
|
||||
: Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
|
||||
cpu(_cpu), _repeatEvent(true)
|
||||
{
|
||||
if (_interval)
|
||||
cpu->schedule(this, curTick() + _interval);
|
||||
}
|
||||
|
||||
void
|
||||
CPUProgressEvent::process()
|
||||
{
|
||||
Counter temp = cpu->totalOps();
|
||||
#ifndef NDEBUG
|
||||
double ipc = double(temp - lastNumInst) / (_interval / cpu->ticks(1));
|
||||
|
||||
DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
|
||||
"%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
|
||||
ipc);
|
||||
ipc = 0.0;
|
||||
#else
|
||||
cprintf("%lli: %s progress event, total committed:%i, progress insts "
|
||||
"committed: %lli\n", curTick(), cpu->name(), temp,
|
||||
temp - lastNumInst);
|
||||
#endif
|
||||
lastNumInst = temp;
|
||||
|
||||
if (_repeatEvent)
|
||||
cpu->schedule(this, curTick() + _interval);
|
||||
}
|
||||
|
||||
const char *
|
||||
CPUProgressEvent::description() const
|
||||
{
|
||||
return "CPU Progress";
|
||||
}
|
||||
|
||||
BaseCPU::BaseCPU(Params *p, bool is_checker)
|
||||
: MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id),
|
||||
_instMasterId(p->system->getMasterId(name() + ".inst")),
|
||||
_dataMasterId(p->system->getMasterId(name() + ".data")),
|
||||
interrupts(p->interrupts),
|
||||
numThreads(p->numThreads), system(p->system),
|
||||
phase(p->phase)
|
||||
{
|
||||
// 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 (numThreads > maxThreadsPerCPU)
|
||||
maxThreadsPerCPU = numThreads;
|
||||
|
||||
// allocate per-thread instruction-based event queues
|
||||
comInstEventQueue = new EventQueue *[numThreads];
|
||||
for (ThreadID tid = 0; tid < numThreads; ++tid)
|
||||
comInstEventQueue[tid] =
|
||||
new EventQueue("instruction-based event queue");
|
||||
|
||||
//
|
||||
// set up instruction-count-based termination events, if any
|
||||
//
|
||||
if (p->max_insts_any_thread != 0) {
|
||||
const char *cause = "a thread reached the max instruction count";
|
||||
for (ThreadID tid = 0; tid < numThreads; ++tid) {
|
||||
Event *event = new SimLoopExitEvent(cause, 0);
|
||||
comInstEventQueue[tid]->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 = numThreads;
|
||||
for (ThreadID tid = 0; tid < numThreads; ++tid) {
|
||||
Event *event = new CountedExitEvent(cause, *counter);
|
||||
comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate per-thread load-based event queues
|
||||
comLoadEventQueue = new EventQueue *[numThreads];
|
||||
for (ThreadID tid = 0; tid < numThreads; ++tid)
|
||||
comLoadEventQueue[tid] = new EventQueue("load-based event queue");
|
||||
|
||||
//
|
||||
// set up instruction-count-based termination events, if any
|
||||
//
|
||||
if (p->max_loads_any_thread != 0) {
|
||||
const char *cause = "a thread reached the max load count";
|
||||
for (ThreadID tid = 0; tid < numThreads; ++tid) {
|
||||
Event *event = new SimLoopExitEvent(cause, 0);
|
||||
comLoadEventQueue[tid]->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 = numThreads;
|
||||
for (ThreadID tid = 0; tid < numThreads; ++tid) {
|
||||
Event *event = new CountedExitEvent(cause, *counter);
|
||||
comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads);
|
||||
}
|
||||
}
|
||||
|
||||
functionTracingEnabled = false;
|
||||
if (p->function_trace) {
|
||||
const string fname = csprintf("ftrace.%s", name());
|
||||
functionTraceStream = simout.find(fname);
|
||||
if (!functionTraceStream)
|
||||
functionTraceStream = simout.create(fname);
|
||||
|
||||
currentFunctionStart = currentFunctionEnd = 0;
|
||||
functionEntryTick = p->function_trace_start;
|
||||
|
||||
if (p->function_trace_start == 0) {
|
||||
functionTracingEnabled = true;
|
||||
} else {
|
||||
typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap;
|
||||
Event *event = new wrap(this, true);
|
||||
schedule(event, p->function_trace_start);
|
||||
}
|
||||
}
|
||||
|
||||
// The interrupts should always be present unless this CPU is
|
||||
// switched in later or in case it is a checker CPU
|
||||
if (!params()->defer_registration && !is_checker) {
|
||||
if (interrupts) {
|
||||
interrupts->setCPU(this);
|
||||
} else {
|
||||
fatal("CPU %s has no interrupt controller.\n"
|
||||
"Ensure createInterruptController() is called.\n", name());
|
||||
}
|
||||
}
|
||||
|
||||
if (FullSystem) {
|
||||
profileEvent = NULL;
|
||||
if (params()->profile)
|
||||
profileEvent = new ProfileEvent(this, params()->profile);
|
||||
}
|
||||
tracer = params()->tracer;
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::enableFunctionTrace()
|
||||
{
|
||||
functionTracingEnabled = true;
|
||||
}
|
||||
|
||||
BaseCPU::~BaseCPU()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::init()
|
||||
{
|
||||
if (!params()->defer_registration)
|
||||
registerThreadContexts();
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::startup()
|
||||
{
|
||||
if (FullSystem) {
|
||||
if (!params()->defer_registration && profileEvent)
|
||||
schedule(profileEvent, curTick());
|
||||
}
|
||||
|
||||
if (params()->progress_interval) {
|
||||
Tick num_ticks = ticks(params()->progress_interval);
|
||||
|
||||
new CPUProgressEvent(this, num_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BaseCPU::regStats()
|
||||
{
|
||||
using namespace Stats;
|
||||
|
||||
numCycles
|
||||
.name(name() + ".numCycles")
|
||||
.desc("number of cpu cycles simulated")
|
||||
;
|
||||
|
||||
numWorkItemsStarted
|
||||
.name(name() + ".numWorkItemsStarted")
|
||||
.desc("number of work items this cpu started")
|
||||
;
|
||||
|
||||
numWorkItemsCompleted
|
||||
.name(name() + ".numWorkItemsCompleted")
|
||||
.desc("number of work items this cpu completed")
|
||||
;
|
||||
|
||||
int size = threadContexts.size();
|
||||
if (size > 1) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
stringstream namestr;
|
||||
ccprintf(namestr, "%s.ctx%d", name(), i);
|
||||
threadContexts[i]->regStats(namestr.str());
|
||||
}
|
||||
} else if (size == 1)
|
||||
threadContexts[0]->regStats(name());
|
||||
}
|
||||
|
||||
MasterPort &
|
||||
BaseCPU::getMasterPort(const string &if_name, int idx)
|
||||
{
|
||||
// Get the right port based on name. This applies to all the
|
||||
// subclasses of the base CPU and relies on their implementation
|
||||
// of getDataPort and getInstPort. In all cases there methods
|
||||
// return a CpuPort pointer.
|
||||
if (if_name == "dcache_port")
|
||||
return getDataPort();
|
||||
else if (if_name == "icache_port")
|
||||
return getInstPort();
|
||||
else
|
||||
return MemObject::getMasterPort(if_name, idx);
|
||||
}
|
||||
|
||||
Tick
|
||||
BaseCPU::nextCycle()
|
||||
{
|
||||
Tick next_tick = curTick() - phase + clock - 1;
|
||||
next_tick -= (next_tick % clock);
|
||||
next_tick += phase;
|
||||
return next_tick;
|
||||
}
|
||||
|
||||
Tick
|
||||
BaseCPU::nextCycle(Tick begin_tick)
|
||||
{
|
||||
Tick next_tick = begin_tick;
|
||||
if (next_tick % clock != 0)
|
||||
next_tick = next_tick - (next_tick % clock) + clock;
|
||||
next_tick += phase;
|
||||
|
||||
assert(next_tick >= curTick());
|
||||
return next_tick;
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::registerThreadContexts()
|
||||
{
|
||||
ThreadID size = threadContexts.size();
|
||||
for (ThreadID tid = 0; tid < size; ++tid) {
|
||||
ThreadContext *tc = threadContexts[tid];
|
||||
|
||||
/** 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 (numThreads == 1)
|
||||
tc->setContextId(system->registerThreadContext(tc, _cpuId));
|
||||
else
|
||||
tc->setContextId(system->registerThreadContext(tc));
|
||||
|
||||
if (!FullSystem)
|
||||
tc->getProcessPtr()->assignThreadContext(tc->contextId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
BaseCPU::findContext(ThreadContext *tc)
|
||||
{
|
||||
ThreadID size = threadContexts.size();
|
||||
for (ThreadID tid = 0; tid < size; ++tid) {
|
||||
if (tc == threadContexts[tid])
|
||||
return tid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::switchOut()
|
||||
{
|
||||
if (profileEvent && profileEvent->scheduled())
|
||||
deschedule(profileEvent);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
assert(threadContexts.size() == oldCPU->threadContexts.size());
|
||||
|
||||
_cpuId = oldCPU->cpuId();
|
||||
|
||||
ThreadID size = threadContexts.size();
|
||||
for (ThreadID i = 0; i < size; ++i) {
|
||||
ThreadContext *newTC = threadContexts[i];
|
||||
ThreadContext *oldTC = oldCPU->threadContexts[i];
|
||||
|
||||
newTC->takeOverFrom(oldTC);
|
||||
|
||||
CpuEvent::replaceThreadContext(oldTC, newTC);
|
||||
|
||||
assert(newTC->contextId() == oldTC->contextId());
|
||||
assert(newTC->threadId() == oldTC->threadId());
|
||||
system->replaceThreadContext(newTC, newTC->contextId());
|
||||
|
||||
/* 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);
|
||||
*/
|
||||
|
||||
MasterPort *old_itb_port = oldTC->getITBPtr()->getMasterPort();
|
||||
MasterPort *old_dtb_port = oldTC->getDTBPtr()->getMasterPort();
|
||||
MasterPort *new_itb_port = newTC->getITBPtr()->getMasterPort();
|
||||
MasterPort *new_dtb_port = newTC->getDTBPtr()->getMasterPort();
|
||||
|
||||
// Move over any table walker ports if they exist
|
||||
if (new_itb_port && !new_itb_port->isConnected()) {
|
||||
assert(old_itb_port);
|
||||
SlavePort &slavePort = old_itb_port->getSlavePort();
|
||||
new_itb_port->bind(slavePort);
|
||||
}
|
||||
if (new_dtb_port && !new_dtb_port->isConnected()) {
|
||||
assert(old_dtb_port);
|
||||
SlavePort &slavePort = old_dtb_port->getSlavePort();
|
||||
new_dtb_port->bind(slavePort);
|
||||
}
|
||||
|
||||
// Checker whether or not we have to transfer CheckerCPU
|
||||
// objects over in the switch
|
||||
CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr();
|
||||
CheckerCPU *newChecker = newTC->getCheckerCpuPtr();
|
||||
if (oldChecker && newChecker) {
|
||||
MasterPort *old_checker_itb_port =
|
||||
oldChecker->getITBPtr()->getMasterPort();
|
||||
MasterPort *old_checker_dtb_port =
|
||||
oldChecker->getDTBPtr()->getMasterPort();
|
||||
MasterPort *new_checker_itb_port =
|
||||
newChecker->getITBPtr()->getMasterPort();
|
||||
MasterPort *new_checker_dtb_port =
|
||||
newChecker->getDTBPtr()->getMasterPort();
|
||||
|
||||
// Move over any table walker ports if they exist for checker
|
||||
if (new_checker_itb_port && !new_checker_itb_port->isConnected()) {
|
||||
assert(old_checker_itb_port);
|
||||
SlavePort &slavePort = old_checker_itb_port->getSlavePort();;
|
||||
new_checker_itb_port->bind(slavePort);
|
||||
}
|
||||
if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) {
|
||||
assert(old_checker_dtb_port);
|
||||
SlavePort &slavePort = old_checker_dtb_port->getSlavePort();;
|
||||
new_checker_dtb_port->bind(slavePort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interrupts = oldCPU->interrupts;
|
||||
interrupts->setCPU(this);
|
||||
|
||||
if (FullSystem) {
|
||||
for (ThreadID i = 0; i < size; ++i)
|
||||
threadContexts[i]->profileClear();
|
||||
|
||||
if (profileEvent)
|
||||
schedule(profileEvent, curTick());
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (!getInstPort().isConnected()) {
|
||||
getInstPort().bind(oldCPU->getInstPort().getSlavePort());
|
||||
}
|
||||
|
||||
if (!getDataPort().isConnected()) {
|
||||
getDataPort().bind(oldCPU->getDataPort().getSlavePort());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval)
|
||||
: cpu(_cpu), interval(_interval)
|
||||
{ }
|
||||
|
||||
void
|
||||
BaseCPU::ProfileEvent::process()
|
||||
{
|
||||
ThreadID size = cpu->threadContexts.size();
|
||||
for (ThreadID i = 0; i < size; ++i) {
|
||||
ThreadContext *tc = cpu->threadContexts[i];
|
||||
tc->profileSample();
|
||||
}
|
||||
|
||||
cpu->schedule(this, curTick() + interval);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::serialize(std::ostream &os)
|
||||
{
|
||||
SERIALIZE_SCALAR(instCnt);
|
||||
interrupts->serialize(os);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
UNSERIALIZE_SCALAR(instCnt);
|
||||
interrupts->unserialize(cp, section);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::traceFunctionsInternal(Addr pc)
|
||||
{
|
||||
if (!debugSymbolTable)
|
||||
return;
|
||||
|
||||
// if pc enters different function, print new function symbol and
|
||||
// update saved range. Otherwise do nothing.
|
||||
if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
|
||||
string sym_str;
|
||||
bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
|
||||
currentFunctionStart,
|
||||
currentFunctionEnd);
|
||||
|
||||
if (!found) {
|
||||
// no symbol found: use addr as label
|
||||
sym_str = csprintf("0x%x", pc);
|
||||
currentFunctionStart = pc;
|
||||
currentFunctionEnd = pc + 1;
|
||||
}
|
||||
|
||||
ccprintf(*functionTraceStream, " (%d)\n%d: %s",
|
||||
curTick() - functionEntryTick, curTick(), sym_str);
|
||||
functionEntryTick = curTick();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCPU::CpuPort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
panic("BaseCPU doesn't expect recvTiming!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::CpuPort::recvRetry()
|
||||
{
|
||||
panic("BaseCPU doesn't expect recvRetry!\n");
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::CpuPort::recvFunctionalSnoop(PacketPtr pkt)
|
||||
{
|
||||
// No internal storage to update (in the general case). A CPU with
|
||||
// internal storage, e.g. an LSQ that should be part of the
|
||||
// coherent memory has to check against stored data.
|
||||
}
|
||||
406
simulators/gem5/src/cpu/base.hh
Normal file
406
simulators/gem5/src/cpu/base.hh
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||
* Copyright (c) 2011 Regents of the University of California
|
||||
* 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: Steve Reinhardt
|
||||
* Nathan Binkert
|
||||
* Rick Strong
|
||||
*/
|
||||
|
||||
#ifndef __CPU_BASE_HH__
|
||||
#define __CPU_BASE_HH__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "arch/interrupts.hh"
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/microcode_rom.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/insttracer.hh"
|
||||
|
||||
struct BaseCPUParams;
|
||||
class BranchPred;
|
||||
class CheckerCPU;
|
||||
class ThreadContext;
|
||||
class System;
|
||||
|
||||
class CPUProgressEvent : public Event
|
||||
{
|
||||
protected:
|
||||
Tick _interval;
|
||||
Counter lastNumInst;
|
||||
BaseCPU *cpu;
|
||||
bool _repeatEvent;
|
||||
|
||||
public:
|
||||
CPUProgressEvent(BaseCPU *_cpu, Tick ival = 0);
|
||||
|
||||
void process();
|
||||
|
||||
void interval(Tick ival) { _interval = ival; }
|
||||
Tick interval() { return _interval; }
|
||||
|
||||
void repeatEvent(bool repeat) { _repeatEvent = repeat; }
|
||||
|
||||
virtual const char *description() const;
|
||||
};
|
||||
|
||||
class BaseCPU : public MemObject
|
||||
{
|
||||
protected:
|
||||
// CPU's clock period in terms of the number of ticks of curTime.
|
||||
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;
|
||||
|
||||
/** instruction side request id that must be placed in all requests */
|
||||
MasterID _instMasterId;
|
||||
|
||||
/** data side request id that must be placed in all requests */
|
||||
MasterID _dataMasterId;
|
||||
|
||||
/**
|
||||
* Define a base class for the CPU ports (instruction and data)
|
||||
* that is refined in the subclasses. This class handles the
|
||||
* common cases, i.e. the functional accesses and the status
|
||||
* changes and address range queries. The default behaviour for
|
||||
* both atomic and timing access is to panic and the corresponding
|
||||
* subclasses have to override these methods.
|
||||
*/
|
||||
class CpuPort : public MasterPort
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a CPU port with a name and a structural owner.
|
||||
*
|
||||
* @param _name port name including the owner
|
||||
* @param _name structural owner of this port
|
||||
*/
|
||||
CpuPort(const std::string& _name, MemObject* _owner) :
|
||||
MasterPort(_name, _owner)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool recvTimingResp(PacketPtr pkt);
|
||||
|
||||
virtual void recvRetry();
|
||||
|
||||
virtual void recvFunctionalSnoop(PacketPtr pkt);
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Purely virtual method that returns a reference to the data
|
||||
* port. All subclasses must implement this method.
|
||||
*
|
||||
* @return a reference to the data port
|
||||
*/
|
||||
virtual CpuPort &getDataPort() = 0;
|
||||
|
||||
/**
|
||||
* Purely virtual method that returns a reference to the instruction
|
||||
* port. All subclasses must implement this method.
|
||||
*
|
||||
* @return a reference to the instruction port
|
||||
*/
|
||||
virtual CpuPort &getInstPort() = 0;
|
||||
|
||||
/** Reads this CPU's ID. */
|
||||
int cpuId() { return _cpuId; }
|
||||
|
||||
/** Reads this CPU's unique data requestor ID */
|
||||
MasterID dataMasterId() { return _dataMasterId; }
|
||||
/** Reads this CPU's unique instruction requestor ID */
|
||||
MasterID instMasterId() { return _instMasterId; }
|
||||
|
||||
/**
|
||||
* Get a master port on this CPU. All CPUs have a data and
|
||||
* instruction port, and this method uses getDataPort and
|
||||
* getInstPort of the subclasses to resolve the two ports.
|
||||
*
|
||||
* @param if_name the port name
|
||||
* @param idx ignored index
|
||||
*
|
||||
* @return a reference to the port with the given name
|
||||
*/
|
||||
MasterPort &getMasterPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
// Tick currentTick;
|
||||
inline Tick frequency() const { return SimClock::Frequency / clock; }
|
||||
inline Tick ticks(int numCycles) const { return clock * numCycles; }
|
||||
inline Tick curCycle() const { return curTick() / clock; }
|
||||
inline Tick tickToCycles(Tick val) const { return val / clock; }
|
||||
inline void workItemBegin() { numWorkItemsStarted++; }
|
||||
inline void workItemEnd() { numWorkItemsCompleted++; }
|
||||
// @todo remove me after debugging with legion done
|
||||
Tick instCount() { return instCnt; }
|
||||
|
||||
/** The next cycle the CPU should be scheduled, given a cache
|
||||
* access or quiesce event returning on this cycle. This function
|
||||
* may return curTick() if the CPU should run on the current cycle.
|
||||
*/
|
||||
Tick nextCycle();
|
||||
|
||||
/** The next cycle the CPU should be scheduled, given a cache
|
||||
* access or quiesce event returning on the given Tick. This
|
||||
* function may return curTick() if the CPU should run on the
|
||||
* current cycle.
|
||||
* @param begin_tick The tick that the event is completing on.
|
||||
*/
|
||||
Tick nextCycle(Tick begin_tick);
|
||||
|
||||
TheISA::MicrocodeRom microcodeRom;
|
||||
|
||||
protected:
|
||||
TheISA::Interrupts *interrupts;
|
||||
|
||||
public:
|
||||
TheISA::Interrupts *
|
||||
getInterruptController()
|
||||
{
|
||||
return interrupts;
|
||||
}
|
||||
|
||||
virtual void wakeup() = 0;
|
||||
|
||||
void
|
||||
postInterrupt(int int_num, int index)
|
||||
{
|
||||
interrupts->post(int_num, index);
|
||||
if (FullSystem)
|
||||
wakeup();
|
||||
}
|
||||
|
||||
void
|
||||
clearInterrupt(int int_num, int index)
|
||||
{
|
||||
interrupts->clear(int_num, index);
|
||||
}
|
||||
|
||||
void
|
||||
clearInterrupts()
|
||||
{
|
||||
interrupts->clearAll();
|
||||
}
|
||||
|
||||
bool
|
||||
checkInterrupts(ThreadContext *tc) const
|
||||
{
|
||||
return FullSystem && interrupts->checkInterrupts(tc);
|
||||
}
|
||||
|
||||
class ProfileEvent : public Event
|
||||
{
|
||||
private:
|
||||
BaseCPU *cpu;
|
||||
Tick interval;
|
||||
|
||||
public:
|
||||
ProfileEvent(BaseCPU *cpu, Tick interval);
|
||||
void process();
|
||||
};
|
||||
ProfileEvent *profileEvent;
|
||||
|
||||
protected:
|
||||
std::vector<ThreadContext *> threadContexts;
|
||||
|
||||
Trace::InstTracer * tracer;
|
||||
|
||||
public:
|
||||
|
||||
// Mask to align PCs to MachInst sized boundaries
|
||||
static const Addr PCMask = ~((Addr)sizeof(TheISA::MachInst) - 1);
|
||||
|
||||
/// Provide access to the tracer pointer
|
||||
Trace::InstTracer * getTracer() { return tracer; }
|
||||
|
||||
/// Notify the CPU that the indicated context is now active. The
|
||||
/// delay parameter indicates the number of ticks to wait before
|
||||
/// executing (typically 0 or 1).
|
||||
virtual void activateContext(ThreadID thread_num, int delay) {}
|
||||
|
||||
/// Notify the CPU that the indicated context is now suspended.
|
||||
virtual void suspendContext(ThreadID thread_num) {}
|
||||
|
||||
/// Notify the CPU that the indicated context is now deallocated.
|
||||
virtual void deallocateContext(ThreadID thread_num) {}
|
||||
|
||||
/// Notify the CPU that the indicated context is now halted.
|
||||
virtual void haltContext(ThreadID thread_num) {}
|
||||
|
||||
/// Given a Thread Context pointer return the thread num
|
||||
int findContext(ThreadContext *tc);
|
||||
|
||||
/// Given a thread num get tho thread context for it
|
||||
ThreadContext *getContext(int tn) { return threadContexts[tn]; }
|
||||
|
||||
public:
|
||||
typedef BaseCPUParams Params;
|
||||
const Params *params() const
|
||||
{ return reinterpret_cast<const Params *>(_params); }
|
||||
BaseCPU(Params *params, bool is_checker = false);
|
||||
virtual ~BaseCPU();
|
||||
|
||||
virtual void init();
|
||||
virtual void startup();
|
||||
virtual void regStats();
|
||||
|
||||
virtual void activateWhenReady(ThreadID tid) {};
|
||||
|
||||
void registerThreadContexts();
|
||||
|
||||
/// Prepare for another CPU to take over execution. When it is
|
||||
/// is ready (drained pipe) it signals the sampler.
|
||||
virtual void switchOut();
|
||||
|
||||
/// Take over execution from the given CPU. Used for warm-up and
|
||||
/// sampling.
|
||||
virtual void takeOverFrom(BaseCPU *);
|
||||
|
||||
/**
|
||||
* Number of threads we're actually simulating (<= SMT_MAX_THREADS).
|
||||
* This is a constant for the duration of the simulation.
|
||||
*/
|
||||
ThreadID numThreads;
|
||||
|
||||
/**
|
||||
* Vector of per-thread instruction-based event queues. Used for
|
||||
* scheduling events based on number of instructions committed by
|
||||
* a particular thread.
|
||||
*/
|
||||
EventQueue **comInstEventQueue;
|
||||
|
||||
/**
|
||||
* Vector of per-thread load-based event queues. Used for
|
||||
* scheduling events based on number of loads committed by
|
||||
*a particular thread.
|
||||
*/
|
||||
EventQueue **comLoadEventQueue;
|
||||
|
||||
System *system;
|
||||
|
||||
Tick phase;
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
* @param os The stream to serialize to.
|
||||
*/
|
||||
virtual void serialize(std::ostream &os);
|
||||
|
||||
/**
|
||||
* Reconstruct the state of this object from a checkpoint.
|
||||
* @param cp The checkpoint use.
|
||||
* @param section The section name of this object
|
||||
*/
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
/**
|
||||
* Return pointer to CPU's branch predictor (NULL if none).
|
||||
* @return Branch predictor pointer.
|
||||
*/
|
||||
virtual BranchPred *getBranchPred() { return NULL; };
|
||||
|
||||
virtual Counter totalInsts() const = 0;
|
||||
|
||||
virtual Counter totalOps() const = 0;
|
||||
|
||||
// Function tracing
|
||||
private:
|
||||
bool functionTracingEnabled;
|
||||
std::ostream *functionTraceStream;
|
||||
Addr currentFunctionStart;
|
||||
Addr currentFunctionEnd;
|
||||
Tick functionEntryTick;
|
||||
void enableFunctionTrace();
|
||||
void traceFunctionsInternal(Addr pc);
|
||||
|
||||
private:
|
||||
static std::vector<BaseCPU *> cpuList; //!< Static global cpu list
|
||||
|
||||
public:
|
||||
void traceFunctions(Addr pc)
|
||||
{
|
||||
if (functionTracingEnabled)
|
||||
traceFunctionsInternal(pc);
|
||||
}
|
||||
|
||||
static int numSimulatedCPUs() { return cpuList.size(); }
|
||||
static Counter numSimulatedInsts()
|
||||
{
|
||||
Counter total = 0;
|
||||
|
||||
int size = cpuList.size();
|
||||
for (int i = 0; i < size; ++i)
|
||||
total += cpuList[i]->totalInsts();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static Counter numSimulatedOps()
|
||||
{
|
||||
Counter total = 0;
|
||||
|
||||
int size = cpuList.size();
|
||||
for (int i = 0; i < size; ++i)
|
||||
total += cpuList[i]->totalOps();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
public:
|
||||
// Number of CPU cycles simulated
|
||||
Stats::Scalar numCycles;
|
||||
Stats::Scalar numWorkItemsStarted;
|
||||
Stats::Scalar numWorkItemsCompleted;
|
||||
};
|
||||
|
||||
#endif // __CPU_BASE_HH__
|
||||
1058
simulators/gem5/src/cpu/base_dyn_inst.hh
Normal file
1058
simulators/gem5/src/cpu/base_dyn_inst.hh
Normal file
File diff suppressed because it is too large
Load Diff
230
simulators/gem5/src/cpu/base_dyn_inst_impl.hh
Normal file
230
simulators/gem5/src/cpu/base_dyn_inst_impl.hh
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved.
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <iostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "base/cprintf.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/DynInst.hh"
|
||||
#include "debug/IQ.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/faults.hh"
|
||||
|
||||
template <class Impl>
|
||||
BaseDynInst<Impl>::BaseDynInst(StaticInstPtr _staticInst,
|
||||
StaticInstPtr _macroop,
|
||||
TheISA::PCState _pc, TheISA::PCState _predPC,
|
||||
InstSeqNum seq_num, ImplCPU *cpu)
|
||||
: staticInst(_staticInst), cpu(cpu), traceData(NULL), macroop(_macroop)
|
||||
{
|
||||
seqNum = seq_num;
|
||||
|
||||
pc = _pc;
|
||||
predPC = _predPC;
|
||||
|
||||
initVars();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
BaseDynInst<Impl>::BaseDynInst(StaticInstPtr _staticInst,
|
||||
StaticInstPtr _macroop)
|
||||
: staticInst(_staticInst), traceData(NULL), macroop(_macroop)
|
||||
{
|
||||
seqNum = 0;
|
||||
initVars();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
BaseDynInst<Impl>::initVars()
|
||||
{
|
||||
memData = NULL;
|
||||
effAddr = 0;
|
||||
physEffAddr = 0;
|
||||
readyRegs = 0;
|
||||
|
||||
status.reset();
|
||||
|
||||
instFlags.reset();
|
||||
instFlags[RecordResult] = true;
|
||||
instFlags[Predicate] = true;
|
||||
|
||||
lqIdx = -1;
|
||||
sqIdx = -1;
|
||||
|
||||
// Eventually make this a parameter.
|
||||
threadNumber = 0;
|
||||
|
||||
// Also make this a parameter, or perhaps get it from xc or cpu.
|
||||
asid = 0;
|
||||
|
||||
// Initialize the fault to be NoFault.
|
||||
fault = NoFault;
|
||||
|
||||
#ifndef NDEBUG
|
||||
++cpu->instcount;
|
||||
|
||||
if (cpu->instcount > 1500) {
|
||||
#ifdef DEBUG
|
||||
cpu->dumpInsts();
|
||||
dumpSNList();
|
||||
#endif
|
||||
assert(cpu->instcount <= 1500);
|
||||
}
|
||||
|
||||
DPRINTF(DynInst,
|
||||
"DynInst: [sn:%lli] Instruction created. Instcount for %s = %i\n",
|
||||
seqNum, cpu->name(), cpu->instcount);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
cpu->snList.insert(seqNum);
|
||||
#endif
|
||||
|
||||
reqToVerify = NULL;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
BaseDynInst<Impl>::~BaseDynInst()
|
||||
{
|
||||
if (memData) {
|
||||
delete [] memData;
|
||||
}
|
||||
|
||||
if (traceData) {
|
||||
delete traceData;
|
||||
}
|
||||
|
||||
fault = NoFault;
|
||||
|
||||
#ifndef NDEBUG
|
||||
--cpu->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
|
||||
|
||||
if (reqToVerify)
|
||||
delete reqToVerify;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
template <class Impl>
|
||||
void
|
||||
BaseDynInst<Impl>::dumpSNList()
|
||||
{
|
||||
std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin();
|
||||
|
||||
int count = 0;
|
||||
while (sn_it != cpu->snList.end()) {
|
||||
cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it));
|
||||
count++;
|
||||
sn_it++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
BaseDynInst<Impl>::dump()
|
||||
{
|
||||
cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
|
||||
std::cout << staticInst->disassemble(pc.instAddr());
|
||||
cprintf("'\n");
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
BaseDynInst<Impl>::dump(std::string &outstring)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "T" << threadNumber << " : 0x" << pc.instAddr() << " "
|
||||
<< staticInst->disassemble(pc.instAddr());
|
||||
|
||||
outstring = s.str();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
BaseDynInst<Impl>::markSrcRegReady()
|
||||
{
|
||||
DPRINTF(IQ, "[sn:%lli] has %d ready out of %d sources. RTI %d)\n",
|
||||
seqNum, readyRegs+1, numSrcRegs(), readyToIssue());
|
||||
if (++readyRegs == numSrcRegs()) {
|
||||
setCanIssue();
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx)
|
||||
{
|
||||
_readySrcRegIdx[src_idx] = true;
|
||||
|
||||
markSrcRegReady();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
bool
|
||||
BaseDynInst<Impl>::eaSrcsReady()
|
||||
{
|
||||
// For now I am assuming 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)
|
||||
|
||||
for (int i = 1; i < numSrcRegs(); ++i) {
|
||||
if (!_readySrcRegIdx[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
35
simulators/gem5/src/cpu/checker/SConsopts
Normal file
35
simulators/gem5/src/cpu/checker/SConsopts
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- mode:python -*-
|
||||
|
||||
# Copyright (c) 2003-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: Steve Reinhardt
|
||||
|
||||
Import('*')
|
||||
|
||||
CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
|
||||
'#include "cpu/checker/cpu.hh"',
|
||||
{ 'CPU_exec_context': 'CheckerCPU' })
|
||||
353
simulators/gem5/src/cpu/checker/cpu.cc
Normal file
353
simulators/gem5/src/cpu/checker/cpu.cc
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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
|
||||
* Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "arch/kernel_stats.hh"
|
||||
#include "arch/vtophys.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "params/CheckerCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/tlb.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
void
|
||||
CheckerCPU::init()
|
||||
{
|
||||
masterId = systemPtr->getMasterId(name());
|
||||
}
|
||||
|
||||
CheckerCPU::CheckerCPU(Params *p)
|
||||
: BaseCPU(p, true), thread(NULL), tc(NULL)
|
||||
{
|
||||
memReq = NULL;
|
||||
curStaticInst = NULL;
|
||||
curMacroStaticInst = NULL;
|
||||
|
||||
numInst = 0;
|
||||
startNumInst = 0;
|
||||
numLoad = 0;
|
||||
startNumLoad = 0;
|
||||
youngestSN = 0;
|
||||
|
||||
changedPC = willChangePC = changedNextPC = false;
|
||||
|
||||
exitOnError = p->exitOnError;
|
||||
warnOnlyOnLoadError = p->warnOnlyOnLoadError;
|
||||
itb = p->itb;
|
||||
dtb = p->dtb;
|
||||
systemPtr = NULL;
|
||||
workload = p->workload;
|
||||
thread = NULL;
|
||||
|
||||
updateOnError = true;
|
||||
}
|
||||
|
||||
CheckerCPU::~CheckerCPU()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::setSystem(System *system)
|
||||
{
|
||||
systemPtr = system;
|
||||
|
||||
if (FullSystem) {
|
||||
thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false);
|
||||
} else {
|
||||
thread = new SimpleThread(this, 0, systemPtr,
|
||||
workload.size() ? workload[0] : NULL,
|
||||
itb, dtb);
|
||||
}
|
||||
|
||||
tc = thread->getTC();
|
||||
threadContexts.push_back(tc);
|
||||
thread->kernelStats = NULL;
|
||||
// Thread should never be null after this
|
||||
assert(thread != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::setIcachePort(CpuPort *icache_port)
|
||||
{
|
||||
icachePort = icache_port;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::setDcachePort(CpuPort *dcache_port)
|
||||
{
|
||||
dcachePort = dcache_port;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::serialize(ostream &os)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::unserialize(Checkpoint *cp, const string §ion)
|
||||
{
|
||||
}
|
||||
|
||||
Fault
|
||||
CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
|
||||
{
|
||||
Fault fault = NoFault;
|
||||
unsigned blockSize = dcachePort->peerBlockSize();
|
||||
int fullSize = size;
|
||||
Addr secondAddr = roundDown(addr + size - 1, blockSize);
|
||||
bool checked_flags = false;
|
||||
bool flags_match = true;
|
||||
Addr pAddr = 0x0;
|
||||
|
||||
|
||||
if (secondAddr > addr)
|
||||
size = secondAddr - addr;
|
||||
|
||||
// Need to account for multiple accesses like the Atomic and TimingSimple
|
||||
while (1) {
|
||||
memReq = new Request();
|
||||
memReq->setVirt(0, addr, size, flags, masterId, thread->pcState().instAddr());
|
||||
|
||||
// translate to physical address
|
||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
|
||||
|
||||
if (!checked_flags && fault == NoFault && unverifiedReq) {
|
||||
flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
|
||||
memReq->getPaddr(), memReq->getFlags());
|
||||
pAddr = memReq->getPaddr();
|
||||
checked_flags = true;
|
||||
}
|
||||
|
||||
// Now do the access
|
||||
if (fault == NoFault &&
|
||||
!memReq->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
PacketPtr pkt = new Packet(memReq,
|
||||
memReq->isLLSC() ?
|
||||
MemCmd::LoadLockedReq :
|
||||
MemCmd::ReadReq);
|
||||
|
||||
pkt->dataStatic(data);
|
||||
|
||||
if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) {
|
||||
// Access memory to see if we have the same data
|
||||
dcachePort->sendFunctional(pkt);
|
||||
} else {
|
||||
// Assume the data is correct if it's an uncached access
|
||||
memcpy(data, unverifiedMemData, size);
|
||||
}
|
||||
|
||||
delete memReq;
|
||||
memReq = NULL;
|
||||
delete pkt;
|
||||
}
|
||||
|
||||
if (fault != NoFault) {
|
||||
if (memReq->isPrefetch()) {
|
||||
fault = NoFault;
|
||||
}
|
||||
delete memReq;
|
||||
memReq = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (memReq != NULL) {
|
||||
delete memReq;
|
||||
}
|
||||
|
||||
//If we don't need to access a second cache line, stop now.
|
||||
if (secondAddr <= addr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup for accessing next cache line
|
||||
data += size;
|
||||
unverifiedMemData += size;
|
||||
size = addr + fullSize - secondAddr;
|
||||
addr = secondAddr;
|
||||
}
|
||||
|
||||
if (!flags_match) {
|
||||
warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
|
||||
curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
|
||||
unverifiedReq->getFlags(), addr, pAddr, flags);
|
||||
handleError();
|
||||
}
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
Fault
|
||||
CheckerCPU::writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
Fault fault = NoFault;
|
||||
bool checked_flags = false;
|
||||
bool flags_match = true;
|
||||
Addr pAddr = 0x0;
|
||||
|
||||
unsigned blockSize = dcachePort->peerBlockSize();
|
||||
int fullSize = size;
|
||||
|
||||
Addr secondAddr = roundDown(addr + size - 1, blockSize);
|
||||
|
||||
if (secondAddr > addr)
|
||||
size = secondAddr - addr;
|
||||
|
||||
// Need to account for a multiple access like Atomic and Timing CPUs
|
||||
while (1) {
|
||||
memReq = new Request();
|
||||
memReq->setVirt(0, addr, size, flags, masterId, thread->pcState().instAddr());
|
||||
|
||||
// translate to physical address
|
||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
|
||||
|
||||
if (!checked_flags && fault == NoFault && unverifiedReq) {
|
||||
flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
|
||||
memReq->getPaddr(), memReq->getFlags());
|
||||
pAddr = memReq->getPaddr();
|
||||
checked_flags = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't actually check memory for the store because there
|
||||
* is no guarantee it has left the lsq yet, and therefore we
|
||||
* can't verify the memory on stores without lsq snooping
|
||||
* enabled. This is left as future work for the Checker: LSQ snooping
|
||||
* and memory validation after stores have committed.
|
||||
*/
|
||||
bool was_prefetch = memReq->isPrefetch();
|
||||
|
||||
delete memReq;
|
||||
|
||||
//If we don't need to access a second cache line, stop now.
|
||||
if (fault != NoFault || secondAddr <= addr)
|
||||
{
|
||||
if (fault != NoFault && was_prefetch) {
|
||||
fault = NoFault;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//Update size and access address
|
||||
size = addr + fullSize - secondAddr;
|
||||
//And access the right address.
|
||||
addr = secondAddr;
|
||||
}
|
||||
|
||||
if (!flags_match) {
|
||||
warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
|
||||
curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
|
||||
unverifiedReq->getFlags(), addr, pAddr, flags);
|
||||
handleError();
|
||||
}
|
||||
|
||||
// Assume the result was the same as the one passed in. This checker
|
||||
// doesn't check if the SC should succeed or fail, it just checks the
|
||||
// value.
|
||||
if (unverifiedReq && res && unverifiedReq->extraDataValid())
|
||||
*res = unverifiedReq->getExtraData();
|
||||
|
||||
// Entire purpose here is to make sure we are getting the
|
||||
// same data to send to the mem system as the CPU did.
|
||||
// Cannot check this is actually what went to memory because
|
||||
// there stores can be in ld/st queue or coherent operations
|
||||
// overwriting values.
|
||||
bool extraData;
|
||||
if (unverifiedReq) {
|
||||
extraData = unverifiedReq->extraDataValid() ?
|
||||
unverifiedReq->getExtraData() : 1;
|
||||
}
|
||||
|
||||
if (unverifiedReq && unverifiedMemData &&
|
||||
memcmp(data, unverifiedMemData, fullSize) && extraData) {
|
||||
warn("%lli: Store value does not match value sent to memory!\
|
||||
data: %#x inst_data: %#x", curTick(), data,
|
||||
unverifiedMemData);
|
||||
handleError();
|
||||
}
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
Addr
|
||||
CheckerCPU::dbg_vtophys(Addr addr)
|
||||
{
|
||||
return vtophys(tc, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the flags set by the Checker and Checkee match.
|
||||
*/
|
||||
bool
|
||||
CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr,
|
||||
Addr pAddr, int flags)
|
||||
{
|
||||
Addr unverifiedVAddr = unverified_req->getVaddr();
|
||||
Addr unverifiedPAddr = unverified_req->getPaddr();
|
||||
int unverifiedFlags = unverified_req->getFlags();
|
||||
|
||||
if (unverifiedVAddr != vAddr ||
|
||||
unverifiedPAddr != pAddr ||
|
||||
unverifiedFlags != flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::dumpAndExit()
|
||||
{
|
||||
warn("%lli: Checker PC:%s",
|
||||
curTick(), thread->pcState());
|
||||
panic("Checker found an error!");
|
||||
}
|
||||
438
simulators/gem5/src/cpu/checker/cpu.hh
Normal file
438
simulators/gem5/src/cpu/checker/cpu.hh
Normal file
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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_CHECKER_CPU_HH__
|
||||
#define __CPU_CHECKER_CPU_HH__
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include "arch/types.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/pc_event.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "debug/Checker.hh"
|
||||
#include "params/CheckerCPU.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
// forward declarations
|
||||
namespace TheISA
|
||||
{
|
||||
class TLB;
|
||||
}
|
||||
|
||||
template <class>
|
||||
class BaseDynInst;
|
||||
class ThreadContext;
|
||||
class Request;
|
||||
|
||||
/**
|
||||
* CheckerCPU class. Dynamically verifies instructions as they are
|
||||
* completed by making sure that the instruction and its results match
|
||||
* the independent execution of the benchmark inside the checker. The
|
||||
* checker verifies instructions in order, regardless of the order in
|
||||
* which instructions complete. There are certain results that can
|
||||
* not be verified, specifically the result of a store conditional or
|
||||
* the values of uncached accesses. In these cases, and with
|
||||
* instructions marked as "IsUnverifiable", the checker assumes that
|
||||
* the value from the main CPU's execution is correct and simply
|
||||
* copies that value. It provides a CheckerThreadContext (see
|
||||
* checker/thread_context.hh) that provides hooks for updating the
|
||||
* Checker's state through any ThreadContext accesses. This allows the
|
||||
* checker to be able to correctly verify instructions, even with
|
||||
* external accesses to the ThreadContext that change state.
|
||||
*/
|
||||
class CheckerCPU : public BaseCPU
|
||||
{
|
||||
protected:
|
||||
typedef TheISA::MachInst MachInst;
|
||||
typedef TheISA::FloatReg FloatReg;
|
||||
typedef TheISA::FloatRegBits FloatRegBits;
|
||||
typedef TheISA::MiscReg MiscReg;
|
||||
|
||||
/** id attached to all issued requests */
|
||||
MasterID masterId;
|
||||
public:
|
||||
virtual void init();
|
||||
|
||||
public:
|
||||
typedef CheckerCPUParams Params;
|
||||
const Params *params() const
|
||||
{ return reinterpret_cast<const Params *>(_params); }
|
||||
CheckerCPU(Params *p);
|
||||
virtual ~CheckerCPU();
|
||||
|
||||
std::vector<Process*> workload;
|
||||
|
||||
void setSystem(System *system);
|
||||
|
||||
System *systemPtr;
|
||||
|
||||
void setIcachePort(CpuPort *icache_port);
|
||||
|
||||
CpuPort *icachePort;
|
||||
|
||||
void setDcachePort(CpuPort *dcache_port);
|
||||
|
||||
CpuPort *dcachePort;
|
||||
|
||||
CpuPort &getDataPort()
|
||||
{
|
||||
panic("Not supported on checker!");
|
||||
return *dcachePort;
|
||||
}
|
||||
|
||||
CpuPort &getInstPort()
|
||||
{
|
||||
panic("Not supported on checker!");
|
||||
return *icachePort;
|
||||
}
|
||||
|
||||
public:
|
||||
// Primary thread being run.
|
||||
SimpleThread *thread;
|
||||
|
||||
ThreadContext *tc;
|
||||
|
||||
TheISA::TLB *itb;
|
||||
TheISA::TLB *dtb;
|
||||
|
||||
Addr dbg_vtophys(Addr addr);
|
||||
|
||||
union Result {
|
||||
uint64_t integer;
|
||||
double dbl;
|
||||
void set(uint64_t i) { integer = i; }
|
||||
void set(double d) { dbl = d; }
|
||||
void get(uint64_t& i) { i = integer; }
|
||||
void get(double& d) { d = dbl; }
|
||||
};
|
||||
|
||||
// ISAs like ARM can have multiple destination registers to check,
|
||||
// keep them all in a std::queue
|
||||
std::queue<Result> result;
|
||||
|
||||
// Pointer to the one memory request.
|
||||
RequestPtr memReq;
|
||||
|
||||
StaticInstPtr curStaticInst;
|
||||
StaticInstPtr curMacroStaticInst;
|
||||
|
||||
// number of simulated instructions
|
||||
Counter numInst;
|
||||
Counter startNumInst;
|
||||
|
||||
std::queue<int> miscRegIdxs;
|
||||
|
||||
TheISA::TLB* getITBPtr() { return itb; }
|
||||
TheISA::TLB* getDTBPtr() { return dtb; }
|
||||
|
||||
virtual Counter totalInsts() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Counter totalOps() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// number of simulated loads
|
||||
Counter numLoad;
|
||||
Counter startNumLoad;
|
||||
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
// 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"); }
|
||||
|
||||
// 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 thread->readIntReg(si->srcRegIdx(idx));
|
||||
}
|
||||
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
return thread->readFloatReg(reg_idx);
|
||||
}
|
||||
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
return thread->readFloatRegBits(reg_idx);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void setResult(T t)
|
||||
{
|
||||
Result instRes;
|
||||
instRes.set(t);
|
||||
result.push(instRes);
|
||||
}
|
||||
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
thread->setIntReg(si->destRegIdx(idx), val);
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
thread->setFloatReg(reg_idx, val);
|
||||
setResult<double>(val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
thread->setFloatRegBits(reg_idx, val);
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
bool readPredicate() { return thread->readPredicate(); }
|
||||
void setPredicate(bool val)
|
||||
{
|
||||
thread->setPredicate(val);
|
||||
}
|
||||
|
||||
TheISA::PCState pcState() { return thread->pcState(); }
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{
|
||||
DPRINTF(Checker, "Changing PC to %s, old PC %s.\n",
|
||||
val, thread->pcState());
|
||||
thread->pcState(val);
|
||||
}
|
||||
Addr instAddr() { return thread->instAddr(); }
|
||||
Addr nextInstAddr() { return thread->nextInstAddr(); }
|
||||
MicroPC microPC() { return thread->microPC(); }
|
||||
//////////////////////////////////////////
|
||||
|
||||
MiscReg readMiscRegNoEffect(int misc_reg)
|
||||
{
|
||||
return thread->readMiscRegNoEffect(misc_reg);
|
||||
}
|
||||
|
||||
MiscReg readMiscReg(int misc_reg)
|
||||
{
|
||||
return thread->readMiscReg(misc_reg);
|
||||
}
|
||||
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
miscRegIdxs.push(misc_reg);
|
||||
return thread->setMiscRegNoEffect(misc_reg, val);
|
||||
}
|
||||
|
||||
void setMiscReg(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
miscRegIdxs.push(misc_reg);
|
||||
return thread->setMiscReg(misc_reg, val);
|
||||
}
|
||||
|
||||
MiscReg readMiscRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->readMiscReg(reg_idx);
|
||||
}
|
||||
|
||||
void setMiscRegOperand(
|
||||
const StaticInst *si, int idx, const MiscReg &val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->setMiscReg(reg_idx, val);
|
||||
}
|
||||
|
||||
#if THE_ISA == MIPS_ISA
|
||||
uint64_t readRegOtherThread(int misc_reg)
|
||||
{
|
||||
panic("MIPS MT not defined for CheckerCPU.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
|
||||
{
|
||||
panic("MIPS MT not defined for CheckerCPU.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
void recordPCChange(const TheISA::PCState &val)
|
||||
{
|
||||
changedPC = true;
|
||||
newPCState = val;
|
||||
}
|
||||
|
||||
void demapPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
this->itb->demapPage(vaddr, asn);
|
||||
this->dtb->demapPage(vaddr, asn);
|
||||
}
|
||||
|
||||
void demapInstPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
this->itb->demapPage(vaddr, asn);
|
||||
}
|
||||
|
||||
void demapDataPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
this->dtb->demapPage(vaddr, asn);
|
||||
}
|
||||
|
||||
Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
|
||||
Fault writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
void setStCondFailures(unsigned sc_failures)
|
||||
{}
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
Fault hwrei() { return thread->hwrei(); }
|
||||
bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
|
||||
void wakeup() { }
|
||||
// Assume that the normal CPU's call to syscall was successful.
|
||||
// The checker's state would have already been updated by the syscall.
|
||||
void syscall(uint64_t callnum) { }
|
||||
|
||||
void handleError()
|
||||
{
|
||||
if (exitOnError)
|
||||
dumpAndExit();
|
||||
}
|
||||
|
||||
bool checkFlags(Request *unverified_req, Addr vAddr,
|
||||
Addr pAddr, int flags);
|
||||
|
||||
void dumpAndExit();
|
||||
|
||||
ThreadContext *tcBase() { return tc; }
|
||||
SimpleThread *threadBase() { return thread; }
|
||||
|
||||
Result unverifiedResult;
|
||||
Request *unverifiedReq;
|
||||
uint8_t *unverifiedMemData;
|
||||
|
||||
bool changedPC;
|
||||
bool willChangePC;
|
||||
TheISA::PCState newPCState;
|
||||
bool changedNextPC;
|
||||
bool exitOnError;
|
||||
bool updateOnError;
|
||||
bool warnOnlyOnLoadError;
|
||||
|
||||
InstSeqNum youngestSN;
|
||||
};
|
||||
|
||||
/**
|
||||
* Templated Checker class. This Checker class is templated on the
|
||||
* DynInstPtr of the instruction type that will be verified. Proper
|
||||
* template instantiations of the Checker must be placed at the bottom
|
||||
* of checker/cpu.cc.
|
||||
*/
|
||||
template <class Impl>
|
||||
class Checker : public CheckerCPU
|
||||
{
|
||||
private:
|
||||
typedef typename Impl::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
Checker(Params *p)
|
||||
: CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
|
||||
{ }
|
||||
|
||||
void switchOut();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
void advancePC(Fault fault);
|
||||
|
||||
void verify(DynInstPtr &inst);
|
||||
|
||||
void validateInst(DynInstPtr &inst);
|
||||
void validateExecution(DynInstPtr &inst);
|
||||
void validateState();
|
||||
|
||||
void copyResult(DynInstPtr &inst, uint64_t mismatch_val, int start_idx);
|
||||
void handlePendingInt();
|
||||
|
||||
private:
|
||||
void handleError(DynInstPtr &inst)
|
||||
{
|
||||
if (exitOnError) {
|
||||
dumpAndExit(inst);
|
||||
} else if (updateOnError) {
|
||||
updateThisCycle = true;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpAndExit(DynInstPtr &inst);
|
||||
|
||||
bool updateThisCycle;
|
||||
|
||||
DynInstPtr unverifiedInst;
|
||||
|
||||
std::list<DynInstPtr> instList;
|
||||
typedef typename std::list<DynInstPtr>::iterator InstListIt;
|
||||
void dumpInsts();
|
||||
};
|
||||
|
||||
#endif // __CPU_CHECKER_CPU_HH__
|
||||
670
simulators/gem5/src/cpu/checker/cpu_impl.hh
Normal file
670
simulators/gem5/src/cpu/checker/cpu_impl.hh
Normal file
@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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
|
||||
* Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/vtophys.hh"
|
||||
#include "base/refcnt.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "debug/Checker.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/stats.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::advancePC(Fault fault)
|
||||
{
|
||||
if (fault != NoFault) {
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
fault->invoke(tc, curStaticInst);
|
||||
thread->decoder.reset();
|
||||
} else {
|
||||
if (curStaticInst) {
|
||||
if (curStaticInst->isLastMicroop())
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
TheISA::PCState pcState = thread->pcState();
|
||||
TheISA::advancePC(pcState, curStaticInst);
|
||||
thread->pcState(pcState);
|
||||
DPRINTF(Checker, "Advancing PC to %s.\n", thread->pcState());
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::handlePendingInt()
|
||||
{
|
||||
DPRINTF(Checker, "IRQ detected at PC: %s with %d insts in buffer\n",
|
||||
thread->pcState(), instList.size());
|
||||
DynInstPtr boundaryInst = NULL;
|
||||
if (!instList.empty()) {
|
||||
// Set the instructions as completed and verify as much as possible.
|
||||
DynInstPtr inst;
|
||||
typename std::list<DynInstPtr>::iterator itr;
|
||||
|
||||
for (itr = instList.begin(); itr != instList.end(); itr++) {
|
||||
(*itr)->setCompleted();
|
||||
}
|
||||
|
||||
inst = instList.front();
|
||||
boundaryInst = instList.back();
|
||||
verify(inst); // verify the instructions
|
||||
inst = NULL;
|
||||
}
|
||||
if ((!boundaryInst && curMacroStaticInst &&
|
||||
curStaticInst->isDelayedCommit() &&
|
||||
!curStaticInst->isLastMicroop()) ||
|
||||
(boundaryInst && boundaryInst->isDelayedCommit() &&
|
||||
!boundaryInst->isLastMicroop())) {
|
||||
panic("%lli: Trying to take an interrupt in middle of "
|
||||
"a non-interuptable instruction!", curTick());
|
||||
}
|
||||
boundaryInst = NULL;
|
||||
thread->decoder.reset();
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::verify(DynInstPtr &completed_inst)
|
||||
{
|
||||
DynInstPtr inst;
|
||||
|
||||
// Make sure serializing instructions are actually
|
||||
// seen as serializing to commit. instList should be
|
||||
// empty in these cases.
|
||||
if ((completed_inst->isSerializing() ||
|
||||
completed_inst->isSerializeBefore()) &&
|
||||
(!instList.empty() ?
|
||||
(instList.front()->seqNum != completed_inst->seqNum) : 0)) {
|
||||
panic("%lli: Instruction sn:%lli at PC %s is serializing before but is"
|
||||
" entering instList with other instructions\n", curTick(),
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
}
|
||||
|
||||
// Either check this instruction, or add it to a list of
|
||||
// instructions waiting to be checked. Instructions must be
|
||||
// checked in program order, so if a store has committed yet not
|
||||
// completed, there may be some instructions that are waiting
|
||||
// behind it that have completed and must be checked.
|
||||
if (!instList.empty()) {
|
||||
if (youngestSN < completed_inst->seqNum) {
|
||||
DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
instList.push_back(completed_inst);
|
||||
youngestSN = completed_inst->seqNum;
|
||||
}
|
||||
|
||||
if (!instList.front()->isCompleted()) {
|
||||
return;
|
||||
} else {
|
||||
inst = instList.front();
|
||||
instList.pop_front();
|
||||
}
|
||||
} else {
|
||||
if (!completed_inst->isCompleted()) {
|
||||
if (youngestSN < completed_inst->seqNum) {
|
||||
DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
instList.push_back(completed_inst);
|
||||
youngestSN = completed_inst->seqNum;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (youngestSN < completed_inst->seqNum) {
|
||||
inst = completed_inst;
|
||||
youngestSN = completed_inst->seqNum;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure a serializing instruction is actually seen as
|
||||
// serializing. instList should be empty here
|
||||
if (inst->isSerializeAfter() && !instList.empty()) {
|
||||
panic("%lli: Instruction sn:%lli at PC %s is serializing after but is"
|
||||
" exiting instList with other instructions\n", curTick(),
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
}
|
||||
unverifiedInst = inst;
|
||||
inst = NULL;
|
||||
|
||||
// Try to check all instructions that are completed, ending if we
|
||||
// run out of instructions to check or if an instruction is not
|
||||
// yet completed.
|
||||
while (1) {
|
||||
DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%s.\n",
|
||||
unverifiedInst->seqNum, unverifiedInst->pcState());
|
||||
unverifiedReq = NULL;
|
||||
unverifiedReq = unverifiedInst->reqToVerify;
|
||||
unverifiedMemData = unverifiedInst->memData;
|
||||
// Make sure results queue is empty
|
||||
while (!result.empty()) {
|
||||
result.pop();
|
||||
}
|
||||
numCycles++;
|
||||
|
||||
Fault fault = NoFault;
|
||||
|
||||
// maintain $r0 semantics
|
||||
thread->setIntReg(ZeroReg, 0);
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
thread->setFloatReg(ZeroReg, 0.0);
|
||||
#endif
|
||||
|
||||
// Check if any recent PC changes match up with anything we
|
||||
// expect to happen. This is mostly to check if traps or
|
||||
// PC-based events have occurred in both the checker and CPU.
|
||||
if (changedPC) {
|
||||
DPRINTF(Checker, "Changed PC recently to %s\n",
|
||||
thread->pcState());
|
||||
if (willChangePC) {
|
||||
if (newPCState == thread->pcState()) {
|
||||
DPRINTF(Checker, "Changed PC matches expected PC\n");
|
||||
} else {
|
||||
warn("%lli: Changed PC does not match expected PC, "
|
||||
"changed: %s, expected: %s",
|
||||
curTick(), thread->pcState(), newPCState);
|
||||
CheckerCPU::handleError();
|
||||
}
|
||||
willChangePC = false;
|
||||
}
|
||||
changedPC = false;
|
||||
}
|
||||
if (changedNextPC) {
|
||||
DPRINTF(Checker, "Changed NextPC recently to %#x\n",
|
||||
thread->nextInstAddr());
|
||||
changedNextPC = false;
|
||||
}
|
||||
|
||||
// Try to fetch the instruction
|
||||
uint64_t fetchOffset = 0;
|
||||
bool fetchDone = false;
|
||||
|
||||
while (!fetchDone) {
|
||||
Addr fetch_PC = thread->instAddr();
|
||||
fetch_PC = (fetch_PC & PCMask) + fetchOffset;
|
||||
|
||||
MachInst machInst;
|
||||
|
||||
// If not in the middle of a macro instruction
|
||||
if (!curMacroStaticInst) {
|
||||
// set up memory request for instruction fetch
|
||||
memReq = new Request(unverifiedInst->threadNumber, fetch_PC,
|
||||
sizeof(MachInst),
|
||||
0,
|
||||
masterId,
|
||||
fetch_PC, thread->contextId(),
|
||||
unverifiedInst->threadNumber);
|
||||
memReq->setVirt(0, fetch_PC, sizeof(MachInst),
|
||||
Request::INST_FETCH, masterId, thread->instAddr());
|
||||
|
||||
|
||||
fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute);
|
||||
|
||||
if (fault != NoFault) {
|
||||
if (unverifiedInst->getFault() == NoFault) {
|
||||
// In this case the instruction was not a dummy
|
||||
// instruction carrying an ITB fault. In the single
|
||||
// threaded case the ITB should still be able to
|
||||
// translate this instruction; in the SMT case it's
|
||||
// possible that its ITB entry was kicked out.
|
||||
warn("%lli: Instruction PC %s was not found in the "
|
||||
"ITB!", curTick(), thread->pcState());
|
||||
handleError(unverifiedInst);
|
||||
|
||||
// go to the next instruction
|
||||
advancePC(NoFault);
|
||||
|
||||
// Give up on an ITB fault..
|
||||
delete memReq;
|
||||
unverifiedInst = NULL;
|
||||
return;
|
||||
} else {
|
||||
// The instruction is carrying an ITB fault. Handle
|
||||
// the fault and see if our results match the CPU on
|
||||
// the next tick().
|
||||
fault = unverifiedInst->getFault();
|
||||
delete memReq;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
PacketPtr pkt = new Packet(memReq, MemCmd::ReadReq);
|
||||
|
||||
pkt->dataStatic(&machInst);
|
||||
icachePort->sendFunctional(pkt);
|
||||
machInst = gtoh(machInst);
|
||||
|
||||
delete memReq;
|
||||
delete pkt;
|
||||
}
|
||||
}
|
||||
|
||||
if (fault == NoFault) {
|
||||
TheISA::PCState pcState = thread->pcState();
|
||||
|
||||
if (isRomMicroPC(pcState.microPC())) {
|
||||
fetchDone = true;
|
||||
curStaticInst =
|
||||
microcodeRom.fetchMicroop(pcState.microPC(), NULL);
|
||||
} else if (!curMacroStaticInst) {
|
||||
//We're not in the middle of a macro instruction
|
||||
StaticInstPtr instPtr = NULL;
|
||||
|
||||
//Predecode, ie bundle up an ExtMachInst
|
||||
thread->decoder.setTC(thread->getTC());
|
||||
//If more fetch data is needed, pass it in.
|
||||
Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
|
||||
thread->decoder.moreBytes(pcState, fetchPC, machInst);
|
||||
|
||||
//If an instruction is ready, decode it.
|
||||
//Otherwise, we'll have to fetch beyond the
|
||||
//MachInst at the current pc.
|
||||
if (thread->decoder.instReady()) {
|
||||
fetchDone = true;
|
||||
instPtr = thread->decoder.decode(pcState);
|
||||
thread->pcState(pcState);
|
||||
} else {
|
||||
fetchDone = false;
|
||||
fetchOffset += sizeof(TheISA::MachInst);
|
||||
}
|
||||
|
||||
//If we decoded an instruction and it's microcoded,
|
||||
//start pulling out micro ops
|
||||
if (instPtr && instPtr->isMacroop()) {
|
||||
curMacroStaticInst = instPtr;
|
||||
curStaticInst =
|
||||
instPtr->fetchMicroop(pcState.microPC());
|
||||
} else {
|
||||
curStaticInst = instPtr;
|
||||
}
|
||||
} else {
|
||||
// Read the next micro op from the macro-op
|
||||
curStaticInst =
|
||||
curMacroStaticInst->fetchMicroop(pcState.microPC());
|
||||
fetchDone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reset decoder on Checker
|
||||
thread->decoder.reset();
|
||||
|
||||
// Check Checker and CPU get same instruction, and record
|
||||
// any faults the CPU may have had.
|
||||
Fault unverifiedFault;
|
||||
if (fault == NoFault) {
|
||||
unverifiedFault = unverifiedInst->getFault();
|
||||
|
||||
// Checks that the instruction matches what we expected it to be.
|
||||
// Checks both the machine instruction and the PC.
|
||||
validateInst(unverifiedInst);
|
||||
}
|
||||
|
||||
// keep an instruction count
|
||||
numInst++;
|
||||
|
||||
|
||||
// Either the instruction was a fault and we should process the fault,
|
||||
// or we should just go ahead execute the instruction. This assumes
|
||||
// that the instruction is properly marked as a fault.
|
||||
if (fault == NoFault) {
|
||||
// Execute Checker instruction and trace
|
||||
if (!unverifiedInst->isUnverifiable()) {
|
||||
Trace::InstRecord *traceData = tracer->getInstRecord(curTick(),
|
||||
tc,
|
||||
curStaticInst,
|
||||
pcState(),
|
||||
curMacroStaticInst);
|
||||
fault = curStaticInst->execute(this, traceData);
|
||||
if (traceData) {
|
||||
traceData->dump();
|
||||
delete traceData;
|
||||
}
|
||||
}
|
||||
|
||||
if (fault == NoFault && unverifiedFault == NoFault) {
|
||||
thread->funcExeInst++;
|
||||
// Checks to make sure instrution results are correct.
|
||||
validateExecution(unverifiedInst);
|
||||
|
||||
if (curStaticInst->isLoad()) {
|
||||
++numLoad;
|
||||
}
|
||||
} else if (fault != NoFault && unverifiedFault == NoFault) {
|
||||
panic("%lli: sn: %lli at PC: %s took a fault in checker "
|
||||
"but not in driver CPU\n", curTick(),
|
||||
unverifiedInst->seqNum, unverifiedInst->pcState());
|
||||
} else if (fault == NoFault && unverifiedFault != NoFault) {
|
||||
panic("%lli: sn: %lli at PC: %s took a fault in driver "
|
||||
"CPU but not in checker\n", curTick(),
|
||||
unverifiedInst->seqNum, unverifiedInst->pcState());
|
||||
}
|
||||
}
|
||||
|
||||
// Take any faults here
|
||||
if (fault != NoFault) {
|
||||
if (FullSystem) {
|
||||
fault->invoke(tc, curStaticInst);
|
||||
willChangePC = true;
|
||||
newPCState = thread->pcState();
|
||||
DPRINTF(Checker, "Fault, PC is now %s\n", newPCState);
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
}
|
||||
} else {
|
||||
advancePC(fault);
|
||||
}
|
||||
|
||||
if (FullSystem) {
|
||||
// @todo: Determine if these should happen only if the
|
||||
// instruction hasn't faulted. In the SimpleCPU case this may
|
||||
// not be true, but in the O3 or Ozone case this may be true.
|
||||
Addr oldpc;
|
||||
int count = 0;
|
||||
do {
|
||||
oldpc = thread->instAddr();
|
||||
system->pcEventQueue.service(tc);
|
||||
count++;
|
||||
} while (oldpc != thread->instAddr());
|
||||
if (count > 1) {
|
||||
willChangePC = true;
|
||||
newPCState = thread->pcState();
|
||||
DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: Optionally can check all registers. (Or just those
|
||||
// that have been modified).
|
||||
validateState();
|
||||
|
||||
// Continue verifying instructions if there's another completed
|
||||
// instruction waiting to be verified.
|
||||
if (instList.empty()) {
|
||||
break;
|
||||
} else if (instList.front()->isCompleted()) {
|
||||
unverifiedInst = NULL;
|
||||
unverifiedInst = instList.front();
|
||||
instList.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
unverifiedInst = NULL;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::switchOut()
|
||||
{
|
||||
instList.clear();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::validateInst(DynInstPtr &inst)
|
||||
{
|
||||
if (inst->instAddr() != thread->instAddr()) {
|
||||
warn("%lli: PCs do not match! Inst: %s, checker: %s",
|
||||
curTick(), inst->pcState(), thread->pcState());
|
||||
if (changedPC) {
|
||||
warn("%lli: Changed PCs recently, may not be an error",
|
||||
curTick());
|
||||
} else {
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
|
||||
if (curStaticInst != inst->staticInst) {
|
||||
warn("%lli: StaticInstPtrs don't match. (%s, %s).\n", curTick(),
|
||||
curStaticInst->getName(), inst->staticInst->getName());
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::validateExecution(DynInstPtr &inst)
|
||||
{
|
||||
uint64_t checker_val;
|
||||
uint64_t inst_val;
|
||||
int idx = -1;
|
||||
bool result_mismatch = false;
|
||||
|
||||
if (inst->isUnverifiable()) {
|
||||
// Unverifiable instructions assume they were executed
|
||||
// properly by the CPU. Grab the result from the
|
||||
// instruction and write it to the register.
|
||||
copyResult(inst, 0, idx);
|
||||
} else if (inst->numDestRegs() > 0 && !result.empty()) {
|
||||
DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n",
|
||||
inst->numDestRegs(), result.size());
|
||||
for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) {
|
||||
result.front().get(checker_val);
|
||||
result.pop();
|
||||
inst_val = 0;
|
||||
inst->template popResult<uint64_t>(inst_val);
|
||||
if (checker_val != inst_val) {
|
||||
result_mismatch = true;
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // Checker CPU checks all the saved results in the dyninst passed by
|
||||
// the cpu model being checked against the saved results present in
|
||||
// the static inst executed in the Checker. Sometimes the number
|
||||
// of saved results differs between the dyninst and static inst, but
|
||||
// this is ok and not a bug. May be worthwhile to try and correct this.
|
||||
|
||||
if (result_mismatch) {
|
||||
warn("%lli: Instruction results do not match! (Values may not "
|
||||
"actually be integers) Inst: %#x, checker: %#x",
|
||||
curTick(), inst_val, checker_val);
|
||||
|
||||
// It's useful to verify load values from memory, but in MP
|
||||
// systems the value obtained at execute may be different than
|
||||
// the value obtained at completion. Similarly DMA can
|
||||
// present the same problem on even UP systems. Thus there is
|
||||
// the option to only warn on loads having a result error.
|
||||
// The load/store queue in Detailed CPU can also cause problems
|
||||
// if load/store forwarding is allowed.
|
||||
if (inst->isLoad() && warnOnlyOnLoadError) {
|
||||
copyResult(inst, inst_val, idx);
|
||||
} else {
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->nextInstAddr() != thread->nextInstAddr()) {
|
||||
warn("%lli: Instruction next PCs do not match! Inst: %#x, "
|
||||
"checker: %#x",
|
||||
curTick(), inst->nextInstAddr(), thread->nextInstAddr());
|
||||
handleError(inst);
|
||||
}
|
||||
|
||||
// Checking side effect registers can be difficult if they are not
|
||||
// checked simultaneously with the execution of the instruction.
|
||||
// This is because other valid instructions may have modified
|
||||
// these registers in the meantime, and their values are not
|
||||
// stored within the DynInst.
|
||||
while (!miscRegIdxs.empty()) {
|
||||
int misc_reg_idx = miscRegIdxs.front();
|
||||
miscRegIdxs.pop();
|
||||
|
||||
if (inst->tcBase()->readMiscRegNoEffect(misc_reg_idx) !=
|
||||
thread->readMiscRegNoEffect(misc_reg_idx)) {
|
||||
warn("%lli: Misc reg idx %i (side effect) does not match! "
|
||||
"Inst: %#x, checker: %#x",
|
||||
curTick(), misc_reg_idx,
|
||||
inst->tcBase()->readMiscRegNoEffect(misc_reg_idx),
|
||||
thread->readMiscRegNoEffect(misc_reg_idx));
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function is weird, if it is called it means the Checker and
|
||||
// O3 have diverged, so panic is called for now. It may be useful
|
||||
// to resynch states and continue if the divergence is a false positive
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::validateState()
|
||||
{
|
||||
if (updateThisCycle) {
|
||||
// Change this back to warn if divergences end up being false positives
|
||||
panic("%lli: Instruction PC %#x results didn't match up, copying all "
|
||||
"registers from main CPU", curTick(), unverifiedInst->instAddr());
|
||||
|
||||
// Terribly convoluted way to make sure O3 model does not implode
|
||||
bool inSyscall = unverifiedInst->thread->inSyscall;
|
||||
unverifiedInst->thread->inSyscall = true;
|
||||
|
||||
// Heavy-weight copying of all registers
|
||||
thread->copyArchRegs(unverifiedInst->tcBase());
|
||||
unverifiedInst->thread->inSyscall = inSyscall;
|
||||
|
||||
// Set curStaticInst to unverifiedInst->staticInst
|
||||
curStaticInst = unverifiedInst->staticInst;
|
||||
// Also advance the PC. Hopefully no PC-based events happened.
|
||||
advancePC(NoFault);
|
||||
updateThisCycle = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
|
||||
int start_idx)
|
||||
{
|
||||
// We've already popped one dest off the queue,
|
||||
// so do the fix-up then start with the next dest reg;
|
||||
if (start_idx >= 0) {
|
||||
RegIndex idx = inst->destRegIdx(start_idx);
|
||||
if (idx < TheISA::FP_Base_DepTag) {
|
||||
thread->setIntReg(idx, mismatch_val);
|
||||
} else if (idx < TheISA::Ctrl_Base_DepTag) {
|
||||
thread->setFloatRegBits(idx, mismatch_val);
|
||||
} else if (idx < TheISA::Max_DepTag) {
|
||||
thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag,
|
||||
mismatch_val);
|
||||
}
|
||||
}
|
||||
start_idx++;
|
||||
uint64_t res = 0;
|
||||
for (int i = start_idx; i < inst->numDestRegs(); i++) {
|
||||
RegIndex idx = inst->destRegIdx(i);
|
||||
inst->template popResult<uint64_t>(res);
|
||||
if (idx < TheISA::FP_Base_DepTag) {
|
||||
thread->setIntReg(idx, res);
|
||||
} else if (idx < TheISA::Ctrl_Base_DepTag) {
|
||||
thread->setFloatRegBits(idx, res);
|
||||
} else if (idx < TheISA::Max_DepTag) {
|
||||
// Try to get the proper misc register index for ARM here...
|
||||
thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag, res);
|
||||
} // else Register is out of range...
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::dumpAndExit(DynInstPtr &inst)
|
||||
{
|
||||
cprintf("Error detected, instruction information:\n");
|
||||
cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
|
||||
"Completed:%i\n",
|
||||
inst->pcState(),
|
||||
inst->nextInstAddr(),
|
||||
inst->seqNum,
|
||||
inst->threadNumber,
|
||||
inst->isCompleted());
|
||||
inst->dump();
|
||||
CheckerCPU::dumpAndExit();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::dumpInsts()
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
InstListIt inst_list_it = --(instList.end());
|
||||
|
||||
cprintf("Inst list size: %i\n", instList.size());
|
||||
|
||||
while (inst_list_it != instList.end())
|
||||
{
|
||||
cprintf("Instruction:%i\n",
|
||||
num);
|
||||
|
||||
cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n"
|
||||
"Completed:%i\n",
|
||||
(*inst_list_it)->pcState(),
|
||||
(*inst_list_it)->seqNum,
|
||||
(*inst_list_it)->threadNumber,
|
||||
(*inst_list_it)->isCompleted());
|
||||
|
||||
cprintf("\n");
|
||||
|
||||
inst_list_it--;
|
||||
++num;
|
||||
}
|
||||
|
||||
}
|
||||
306
simulators/gem5/src/cpu/checker/thread_context.hh
Normal file
306
simulators/gem5/src/cpu/checker/thread_context.hh
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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_CHECKER_THREAD_CONTEXT_HH__
|
||||
#define __CPU_CHECKER_THREAD_CONTEXT_HH__
|
||||
|
||||
#include "arch/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Checker.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
namespace TheISA {
|
||||
namespace Kernel {
|
||||
class Statistics;
|
||||
};
|
||||
class Decoder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Derived ThreadContext class for use with the Checker. The template
|
||||
* parameter is the ThreadContext class used by the specific CPU being
|
||||
* verified. This CheckerThreadContext is then used by the main CPU
|
||||
* in place of its usual ThreadContext class. It handles updating the
|
||||
* checker's state any time state is updated externally through the
|
||||
* ThreadContext.
|
||||
*/
|
||||
template <class TC>
|
||||
class CheckerThreadContext : public ThreadContext
|
||||
{
|
||||
public:
|
||||
CheckerThreadContext(TC *actual_tc,
|
||||
CheckerCPU *checker_cpu)
|
||||
: actualTC(actual_tc), checkerTC(checker_cpu->thread),
|
||||
checkerCPU(checker_cpu)
|
||||
{ }
|
||||
|
||||
private:
|
||||
/** The main CPU's ThreadContext, or class that implements the
|
||||
* ThreadContext interface. */
|
||||
TC *actualTC;
|
||||
/** The checker's own SimpleThread. Will be updated any time
|
||||
* anything uses this ThreadContext to externally update a
|
||||
* thread's state. */
|
||||
SimpleThread *checkerTC;
|
||||
/** Pointer to the checker CPU. */
|
||||
CheckerCPU *checkerCPU;
|
||||
|
||||
public:
|
||||
|
||||
BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
|
||||
|
||||
int cpuId() { return actualTC->cpuId(); }
|
||||
|
||||
int contextId() { return actualTC->contextId(); }
|
||||
|
||||
void setContextId(int id)
|
||||
{
|
||||
actualTC->setContextId(id);
|
||||
checkerTC->setContextId(id);
|
||||
}
|
||||
|
||||
/** Returns this thread's ID number. */
|
||||
int threadId() { return actualTC->threadId(); }
|
||||
void setThreadId(int id)
|
||||
{
|
||||
checkerTC->setThreadId(id);
|
||||
actualTC->setThreadId(id);
|
||||
}
|
||||
|
||||
TheISA::TLB *getITBPtr() { return actualTC->getITBPtr(); }
|
||||
|
||||
TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); }
|
||||
|
||||
CheckerCPU *getCheckerCpuPtr()
|
||||
{
|
||||
return checkerCPU;
|
||||
}
|
||||
|
||||
TheISA::Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
|
||||
|
||||
System *getSystemPtr() { return actualTC->getSystemPtr(); }
|
||||
|
||||
TheISA::Kernel::Statistics *getKernelStats()
|
||||
{ return actualTC->getKernelStats(); }
|
||||
|
||||
Process *getProcessPtr() { return actualTC->getProcessPtr(); }
|
||||
|
||||
PortProxy &getPhysProxy() { return actualTC->getPhysProxy(); }
|
||||
|
||||
FSTranslatingPortProxy &getVirtProxy()
|
||||
{ return actualTC->getVirtProxy(); }
|
||||
|
||||
void initMemProxies(ThreadContext *tc)
|
||||
{ actualTC->initMemProxies(tc); }
|
||||
|
||||
void connectMemPorts(ThreadContext *tc)
|
||||
{
|
||||
actualTC->connectMemPorts(tc);
|
||||
}
|
||||
|
||||
SETranslatingPortProxy &getMemProxy() { return actualTC->getMemProxy(); }
|
||||
|
||||
/** Executes a syscall in SE mode. */
|
||||
void syscall(int64_t callnum)
|
||||
{ return actualTC->syscall(callnum); }
|
||||
|
||||
Status status() const { return actualTC->status(); }
|
||||
|
||||
void setStatus(Status new_status)
|
||||
{
|
||||
actualTC->setStatus(new_status);
|
||||
checkerTC->setStatus(new_status);
|
||||
}
|
||||
|
||||
/// Set the status to Active. Optional delay indicates number of
|
||||
/// cycles to wait before beginning execution.
|
||||
void activate(int delay = 1) { actualTC->activate(delay); }
|
||||
|
||||
/// Set the status to Suspended.
|
||||
void suspend(int delay) { actualTC->suspend(delay); }
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt(int delay) { actualTC->halt(delay); }
|
||||
|
||||
void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
|
||||
|
||||
void takeOverFrom(ThreadContext *oldContext)
|
||||
{
|
||||
actualTC->takeOverFrom(oldContext);
|
||||
checkerTC->copyState(oldContext);
|
||||
}
|
||||
|
||||
void regStats(const std::string &name)
|
||||
{
|
||||
actualTC->regStats(name);
|
||||
checkerTC->regStats(name);
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) { actualTC->serialize(os); }
|
||||
void unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{ actualTC->unserialize(cp, section); }
|
||||
|
||||
EndQuiesceEvent *getQuiesceEvent() { return actualTC->getQuiesceEvent(); }
|
||||
|
||||
Tick readLastActivate() { return actualTC->readLastActivate(); }
|
||||
Tick readLastSuspend() { return actualTC->readLastSuspend(); }
|
||||
|
||||
void profileClear() { return actualTC->profileClear(); }
|
||||
void profileSample() { return actualTC->profileSample(); }
|
||||
|
||||
// @todo: Do I need this?
|
||||
void copyArchRegs(ThreadContext *tc)
|
||||
{
|
||||
actualTC->copyArchRegs(tc);
|
||||
checkerTC->copyArchRegs(tc);
|
||||
}
|
||||
|
||||
void clearArchRegs()
|
||||
{
|
||||
actualTC->clearArchRegs();
|
||||
checkerTC->clearArchRegs();
|
||||
}
|
||||
|
||||
//
|
||||
// New accessors for new decoder.
|
||||
//
|
||||
uint64_t readIntReg(int reg_idx)
|
||||
{ return actualTC->readIntReg(reg_idx); }
|
||||
|
||||
FloatReg readFloatReg(int reg_idx)
|
||||
{ return actualTC->readFloatReg(reg_idx); }
|
||||
|
||||
FloatRegBits readFloatRegBits(int reg_idx)
|
||||
{ return actualTC->readFloatRegBits(reg_idx); }
|
||||
|
||||
void setIntReg(int reg_idx, uint64_t val)
|
||||
{
|
||||
actualTC->setIntReg(reg_idx, val);
|
||||
checkerTC->setIntReg(reg_idx, val);
|
||||
}
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val)
|
||||
{
|
||||
actualTC->setFloatReg(reg_idx, val);
|
||||
checkerTC->setFloatReg(reg_idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegBits(int reg_idx, FloatRegBits val)
|
||||
{
|
||||
actualTC->setFloatRegBits(reg_idx, val);
|
||||
checkerTC->setFloatRegBits(reg_idx, val);
|
||||
}
|
||||
|
||||
/** Reads this thread's PC state. */
|
||||
TheISA::PCState pcState()
|
||||
{ return actualTC->pcState(); }
|
||||
|
||||
/** Sets this thread's PC state. */
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{
|
||||
DPRINTF(Checker, "Changing PC to %s, old PC %s\n",
|
||||
val, checkerTC->pcState());
|
||||
checkerTC->pcState(val);
|
||||
checkerCPU->recordPCChange(val);
|
||||
return actualTC->pcState(val);
|
||||
}
|
||||
|
||||
void pcStateNoRecord(const TheISA::PCState &val)
|
||||
{
|
||||
return actualTC->pcState(val);
|
||||
}
|
||||
|
||||
/** Reads this thread's PC. */
|
||||
Addr instAddr()
|
||||
{ return actualTC->instAddr(); }
|
||||
|
||||
/** Reads this thread's next PC. */
|
||||
Addr nextInstAddr()
|
||||
{ return actualTC->nextInstAddr(); }
|
||||
|
||||
/** Reads this thread's next PC. */
|
||||
MicroPC microPC()
|
||||
{ return actualTC->microPC(); }
|
||||
|
||||
MiscReg readMiscRegNoEffect(int misc_reg)
|
||||
{ return actualTC->readMiscRegNoEffect(misc_reg); }
|
||||
|
||||
MiscReg readMiscReg(int misc_reg)
|
||||
{ return actualTC->readMiscReg(misc_reg); }
|
||||
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
DPRINTF(Checker, "Setting misc reg with no effect: %d to both Checker"
|
||||
" and O3..\n", misc_reg);
|
||||
checkerTC->setMiscRegNoEffect(misc_reg, val);
|
||||
actualTC->setMiscRegNoEffect(misc_reg, val);
|
||||
}
|
||||
|
||||
void setMiscReg(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
DPRINTF(Checker, "Setting misc reg with effect: %d to both Checker"
|
||||
" and O3..\n", misc_reg);
|
||||
checkerTC->setMiscReg(misc_reg, val);
|
||||
actualTC->setMiscReg(misc_reg, val);
|
||||
}
|
||||
|
||||
int flattenIntIndex(int reg) { return actualTC->flattenIntIndex(reg); }
|
||||
int flattenFloatIndex(int reg) { return actualTC->flattenFloatIndex(reg); }
|
||||
|
||||
unsigned readStCondFailures()
|
||||
{ return actualTC->readStCondFailures(); }
|
||||
|
||||
void setStCondFailures(unsigned sc_failures)
|
||||
{
|
||||
actualTC->setStCondFailures(sc_failures);
|
||||
}
|
||||
|
||||
// @todo: Fix this!
|
||||
bool misspeculating() { return actualTC->misspeculating(); }
|
||||
|
||||
Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
|
||||
};
|
||||
|
||||
#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__
|
||||
61
simulators/gem5/src/cpu/cpuevent.cc
Normal file
61
simulators/gem5/src/cpu/cpuevent.cc
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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: Ali Saidi
|
||||
*/
|
||||
|
||||
#include "cpu/cpuevent.hh"
|
||||
|
||||
/** Static list of all CpuEvent objects so we can modify their thread
|
||||
* contexts as needed. */
|
||||
CpuEvent::CpuEventList CpuEvent::cpuEventList;
|
||||
|
||||
CpuEvent::~CpuEvent()
|
||||
{
|
||||
CpuEventList::iterator i;
|
||||
|
||||
// delete the event from the global list
|
||||
for (i = cpuEventList.begin(); i != cpuEventList.end(); ) {
|
||||
if (*i == this)
|
||||
i = cpuEventList.erase(i);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CpuEvent::replaceThreadContext(ThreadContext *oldTc, ThreadContext *newTc)
|
||||
{
|
||||
CpuEventList::iterator i;
|
||||
|
||||
// Update any events that have the old thread context with the new thread
|
||||
// context
|
||||
for (i = cpuEventList.begin(); i != cpuEventList.end(); i++) {
|
||||
if ((*i)->tc == oldTc)
|
||||
(*i)->tc = newTc;
|
||||
}
|
||||
}
|
||||
92
simulators/gem5/src/cpu/cpuevent.hh
Normal file
92
simulators/gem5/src/cpu/cpuevent.hh
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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: Ali Saidi
|
||||
*/
|
||||
|
||||
#ifndef __CPU_CPUEVENT_HH__
|
||||
#define __CPU_CPUEVENT_HH__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
class ThreadContext;
|
||||
|
||||
/**
|
||||
* This class creates a global list of events that need a pointer to a
|
||||
* thread context. When a switchover takes place the events can be
|
||||
* migrated to the new thread context, otherwise you could have a wake
|
||||
* timer interrupt go off on a switched out cpu or other unfortunate
|
||||
* events. This object MUST be dynamically allocated to avoid it being
|
||||
* deleted after a cpu switch happens.
|
||||
*/
|
||||
class CpuEvent : public Event
|
||||
{
|
||||
protected:
|
||||
/** type of global list of cpu events. */
|
||||
typedef std::vector<CpuEvent *> CpuEventList;
|
||||
|
||||
/** Static list of cpu events that is searched every time a cpu switch
|
||||
* happens. */
|
||||
static CpuEventList cpuEventList;
|
||||
|
||||
/** The thread context that is switched to the new cpus. */
|
||||
ThreadContext *tc;
|
||||
|
||||
public:
|
||||
CpuEvent(ThreadContext *_tc, Priority p = Default_Pri)
|
||||
: Event(p), tc(_tc)
|
||||
{ cpuEventList.push_back(this); }
|
||||
|
||||
/** delete the cpu event from the global list. */
|
||||
~CpuEvent();
|
||||
|
||||
/** Update all events switching old tc to new tc.
|
||||
* @param oldTc the old thread context we are switching from
|
||||
* @param newTc the new thread context we are switching to.
|
||||
*/
|
||||
static void replaceThreadContext(ThreadContext *oldTc,
|
||||
ThreadContext *newTc);
|
||||
ThreadContext* getTC() { return tc; }
|
||||
};
|
||||
|
||||
template <class T, void (T::* F)(ThreadContext *tc)>
|
||||
class CpuEventWrapper : public CpuEvent
|
||||
{
|
||||
private:
|
||||
T *object;
|
||||
|
||||
public:
|
||||
CpuEventWrapper(T *obj, ThreadContext *_tc, Priority p = Default_Pri)
|
||||
: CpuEvent(_tc, p), object(obj)
|
||||
{ }
|
||||
void process() { (object->*F)(tc); }
|
||||
};
|
||||
|
||||
#endif // __CPU_CPUEVENT_HH__
|
||||
|
||||
129
simulators/gem5/src/cpu/decode_cache.hh
Normal file
129
simulators/gem5/src/cpu/decode_cache.hh
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Google
|
||||
* 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_DECODE_CACHE_HH__
|
||||
#define __CPU_DECODE_CACHE_HH__
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/types.hh"
|
||||
#include "base/hashmap.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/static_inst_fwd.hh"
|
||||
|
||||
namespace TheISA
|
||||
{
|
||||
class Decoder;
|
||||
}
|
||||
|
||||
namespace DecodeCache
|
||||
{
|
||||
|
||||
/// Hash for decoded instructions.
|
||||
typedef m5::hash_map<TheISA::ExtMachInst, StaticInstPtr> InstMap;
|
||||
|
||||
/// A sparse map from an Addr to a Value, stored in page chunks.
|
||||
template<class Value>
|
||||
class AddrMap
|
||||
{
|
||||
protected:
|
||||
// A pages worth of cache entries.
|
||||
struct CachePage {
|
||||
Value items[TheISA::PageBytes];
|
||||
};
|
||||
// A map of cache pages which allows a sparse mapping.
|
||||
typedef typename m5::hash_map<Addr, CachePage *> PageMap;
|
||||
typedef typename PageMap::iterator PageIt;
|
||||
// Mini cache of recent lookups.
|
||||
PageIt recent[2];
|
||||
PageMap pageMap;
|
||||
|
||||
/// Update the mini cache of recent lookups.
|
||||
/// @param recentest The most recent result;
|
||||
void
|
||||
update(PageIt recentest)
|
||||
{
|
||||
recent[1] = recent[0];
|
||||
recent[0] = recentest;
|
||||
}
|
||||
|
||||
/// Attempt to find the CacheePage which goes with a particular
|
||||
/// address. First check the small cache of recent results, then
|
||||
/// actually look in the hash_map.
|
||||
/// @param addr The address to look up.
|
||||
CachePage *
|
||||
getPage(Addr addr)
|
||||
{
|
||||
Addr page_addr = addr & ~(TheISA::PageBytes - 1);
|
||||
|
||||
// Check against recent lookups.
|
||||
if (recent[0] != pageMap.end()) {
|
||||
if (recent[0]->first == page_addr)
|
||||
return recent[0]->second;
|
||||
if (recent[1] != pageMap.end() &&
|
||||
recent[1]->first == page_addr) {
|
||||
update(recent[1]);
|
||||
// recent[1] has just become recent[0].
|
||||
return recent[0]->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Actually look in the has_map.
|
||||
PageIt it = pageMap.find(page_addr);
|
||||
if (it != pageMap.end()) {
|
||||
update(it);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Didn't find an existing page, so add a new one.
|
||||
CachePage *newPage = new CachePage;
|
||||
page_addr = page_addr & ~(TheISA::PageBytes - 1);
|
||||
typename PageMap::value_type to_insert(page_addr, newPage);
|
||||
update(pageMap.insert(to_insert).first);
|
||||
return newPage;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
AddrMap()
|
||||
{
|
||||
recent[0] = recent[1] = pageMap.end();
|
||||
}
|
||||
|
||||
Value &
|
||||
lookup(Addr addr)
|
||||
{
|
||||
CachePage *page = getPage(addr);
|
||||
return page->items[addr & (TheISA::PageBytes - 1)];
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace DecodeCache
|
||||
|
||||
#endif // __CPU_DECODE_CACHE_HH__
|
||||
98
simulators/gem5/src/cpu/dummy_checker_builder.cc
Normal file
98
simulators/gem5/src/cpu/dummy_checker_builder.cc
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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: Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/DummyChecker.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class MemObject;
|
||||
|
||||
/**
|
||||
* Specific non-templated derived class used for SimObject configuration.
|
||||
*/
|
||||
class DummyChecker : public CheckerCPU
|
||||
{
|
||||
public:
|
||||
DummyChecker(Params *p)
|
||||
: CheckerCPU(p)
|
||||
{ }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DummyChecker Simulation Object
|
||||
//
|
||||
DummyChecker *
|
||||
DummyCheckerParams::create()
|
||||
{
|
||||
DummyChecker::Params *params = new DummyChecker::Params();
|
||||
params->name = name;
|
||||
params->numThreads = numThreads;
|
||||
params->max_insts_any_thread = 0;
|
||||
params->max_insts_all_threads = 0;
|
||||
params->max_loads_any_thread = 0;
|
||||
params->max_loads_all_threads = 0;
|
||||
params->clock = clock;
|
||||
// Hack to touch all parameters. Consider not deriving Checker
|
||||
// from BaseCPU..it's not really a CPU in the end.
|
||||
Counter temp;
|
||||
temp = max_insts_any_thread;
|
||||
temp = max_insts_all_threads;
|
||||
temp = max_loads_any_thread;
|
||||
temp = max_loads_all_threads;
|
||||
temp++;
|
||||
Tick temp2 = progress_interval;
|
||||
params->progress_interval = 0;
|
||||
temp2++;
|
||||
|
||||
params->itb = itb;
|
||||
params->dtb = dtb;
|
||||
params->system = system;
|
||||
params->cpu_id = cpu_id;
|
||||
params->profile = profile;
|
||||
params->interrupts = NULL;
|
||||
params->workload = workload;
|
||||
|
||||
DummyChecker *cpu = new DummyChecker(params);
|
||||
return cpu;
|
||||
}
|
||||
129
simulators/gem5/src/cpu/exec_context.hh
Normal file
129
simulators/gem5/src/cpu/exec_context.hh
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2002-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
|
||||
*/
|
||||
|
||||
#error "Cannot include this file"
|
||||
|
||||
/**
|
||||
* The ExecContext is not a usable class. It is simply here for
|
||||
* documentation purposes. It shows the interface that is used by the
|
||||
* ISA to access and change CPU state.
|
||||
*/
|
||||
class ExecContext {
|
||||
// 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 reduce 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).
|
||||
|
||||
/** Reads an integer register. */
|
||||
uint64_t readIntRegOperand(const StaticInst *si, int idx);
|
||||
|
||||
/** Reads a floating point register of single register width. */
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx);
|
||||
|
||||
/** Reads a floating point register in its binary format, instead
|
||||
* of by value. */
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx);
|
||||
|
||||
/** Sets an integer register to a value. */
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val);
|
||||
|
||||
/** Sets a floating point register of single width to a value. */
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val);
|
||||
|
||||
/** Sets the bits of a floating point register of single width
|
||||
* to a binary value. */
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val);
|
||||
|
||||
/** Reads the PC. */
|
||||
uint64_t readPC();
|
||||
/** Reads the NextPC. */
|
||||
uint64_t readNextPC();
|
||||
/** Reads the Next-NextPC. Only for architectures like SPARC or MIPS. */
|
||||
uint64_t readNextNPC();
|
||||
|
||||
/** Sets the PC. */
|
||||
void setPC(uint64_t val);
|
||||
/** Sets the NextPC. */
|
||||
void setNextPC(uint64_t val);
|
||||
/** Sets the Next-NextPC. Only for architectures like SPARC or MIPS. */
|
||||
void setNextNPC(uint64_t val);
|
||||
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscRegNoEffect(int misc_reg);
|
||||
|
||||
/** Reads a miscellaneous register, handling any architectural
|
||||
* side effects due to reading that register. */
|
||||
MiscReg readMiscReg(int misc_reg);
|
||||
|
||||
/** Sets a miscellaneous register. */
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
|
||||
|
||||
/** Sets a miscellaneous register, handling any architectural
|
||||
* side effects due to writing that register. */
|
||||
void setMiscReg(int misc_reg, const MiscReg &val);
|
||||
|
||||
/** Records the effective address of the instruction. Only valid
|
||||
* for memory ops. */
|
||||
void setEA(Addr EA);
|
||||
/** Returns the effective address of the instruction. Only valid
|
||||
* for memory ops. */
|
||||
Addr getEA();
|
||||
|
||||
/** Returns a pointer to the ThreadContext. */
|
||||
ThreadContext *tcBase();
|
||||
|
||||
Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
Fault writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
/** Somewhat Alpha-specific function that handles returning from
|
||||
* an error or interrupt. */
|
||||
Fault hwrei();
|
||||
|
||||
/**
|
||||
* Check for special simulator handling of specific PAL calls. If
|
||||
* return value is false, actual PAL call will be suppressed.
|
||||
*/
|
||||
bool simPalCheck(int palFunc);
|
||||
|
||||
/** Executes a syscall specified by the callnum. */
|
||||
void syscall(int64_t callnum);
|
||||
|
||||
/** Finish a DTB address translation. */
|
||||
void finishTranslation(WholeTranslationState *state);
|
||||
};
|
||||
174
simulators/gem5/src/cpu/exetrace.cc
Normal file
174
simulators/gem5/src/cpu/exetrace.cc
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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: Steve Reinhardt
|
||||
* Lisa Hsu
|
||||
* Nathan Binkert
|
||||
* Steve Raasch
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/utility.hh"
|
||||
#include "base/loader/symtab.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/ExecAll.hh"
|
||||
#include "enums/OpClass.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
namespace Trace {
|
||||
|
||||
void
|
||||
ExeTracerRecord::dumpTicks(ostream &outs)
|
||||
{
|
||||
ccprintf(outs, "%7d: ", when);
|
||||
}
|
||||
|
||||
void
|
||||
Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran)
|
||||
{
|
||||
ostream &outs = Trace::output();
|
||||
|
||||
if (!Debug::ExecUser || !Debug::ExecKernel) {
|
||||
bool in_user_mode = TheISA::inUserMode(thread);
|
||||
if (in_user_mode && !Debug::ExecUser) return;
|
||||
if (!in_user_mode && !Debug::ExecKernel) return;
|
||||
}
|
||||
|
||||
if (Debug::ExecTicks)
|
||||
dumpTicks(outs);
|
||||
|
||||
outs << thread->getCpuPtr()->name() << " ";
|
||||
|
||||
if (Debug::ExecSpeculative)
|
||||
outs << (misspeculating ? "-" : "+") << " ";
|
||||
|
||||
if (Debug::ExecAsid)
|
||||
outs << "A" << dec << TheISA::getExecutingAsid(thread) << " ";
|
||||
|
||||
if (Debug::ExecThread)
|
||||
outs << "T" << thread->threadId() << " : ";
|
||||
|
||||
std::string sym_str;
|
||||
Addr sym_addr;
|
||||
Addr cur_pc = pc.instAddr();
|
||||
if (debugSymbolTable && Debug::ExecSymbol && !inUserMode(thread)
|
||||
&& debugSymbolTable->findNearestSymbol(cur_pc, sym_str, sym_addr)) {
|
||||
if (cur_pc != sym_addr)
|
||||
sym_str += csprintf("+%d",cur_pc - sym_addr);
|
||||
outs << "@" << sym_str;
|
||||
} else {
|
||||
outs << "0x" << hex << cur_pc;
|
||||
}
|
||||
|
||||
if (inst->isMicroop()) {
|
||||
outs << "." << setw(2) << dec << pc.microPC();
|
||||
} else {
|
||||
outs << " ";
|
||||
}
|
||||
|
||||
outs << " : ";
|
||||
|
||||
//
|
||||
// Print decoded instruction
|
||||
//
|
||||
|
||||
outs << setw(26) << left;
|
||||
outs << inst->disassemble(cur_pc, debugSymbolTable);
|
||||
|
||||
if (ran) {
|
||||
outs << " : ";
|
||||
|
||||
if (Debug::ExecOpClass) {
|
||||
outs << Enums::OpClassStrings[inst->opClass()] << " : ";
|
||||
}
|
||||
|
||||
if (Debug::ExecResult && predicate == false) {
|
||||
outs << "Predicated False";
|
||||
}
|
||||
|
||||
if (Debug::ExecResult && data_status != DataInvalid) {
|
||||
ccprintf(outs, " D=%#018x", data.as_int);
|
||||
}
|
||||
|
||||
if (Debug::ExecEffAddr && addr_valid)
|
||||
outs << " A=0x" << hex << addr;
|
||||
|
||||
if (Debug::ExecFetchSeq && fetch_seq_valid)
|
||||
outs << " FetchSeq=" << dec << fetch_seq;
|
||||
|
||||
if (Debug::ExecCPSeq && cp_seq_valid)
|
||||
outs << " CPSeq=" << dec << cp_seq;
|
||||
}
|
||||
|
||||
//
|
||||
// End of line...
|
||||
//
|
||||
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 (Debug::ExecMacro && staticInst->isMicroop() &&
|
||||
((Debug::ExecMicro &&
|
||||
macroStaticInst && staticInst->isFirstMicroop()) ||
|
||||
(!Debug::ExecMicro &&
|
||||
macroStaticInst && staticInst->isLastMicroop()))) {
|
||||
traceInst(macroStaticInst, false);
|
||||
}
|
||||
if (Debug::ExecMicro || !staticInst->isMicroop()) {
|
||||
traceInst(staticInst, true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ExeTracer Simulation Object
|
||||
//
|
||||
Trace::ExeTracer *
|
||||
ExeTracerParams::create()
|
||||
{
|
||||
return new Trace::ExeTracer(this);
|
||||
}
|
||||
93
simulators/gem5/src/cpu/exetrace.hh
Normal file
93
simulators/gem5/src/cpu/exetrace.hh
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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: Steve Reinhardt
|
||||
* Nathan Binkert
|
||||
*/
|
||||
|
||||
#ifndef __CPU_EXETRACE_HH__
|
||||
#define __CPU_EXETRACE_HH__
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "base/types.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/ExecEnable.hh"
|
||||
#include "debug/ExecSpeculative.hh"
|
||||
#include "params/ExeTracer.hh"
|
||||
#include "sim/insttracer.hh"
|
||||
|
||||
class ThreadContext;
|
||||
|
||||
namespace Trace {
|
||||
|
||||
class ExeTracerRecord : public InstRecord
|
||||
{
|
||||
public:
|
||||
ExeTracerRecord(Tick _when, ThreadContext *_thread,
|
||||
const StaticInstPtr _staticInst, TheISA::PCState _pc,
|
||||
bool spec, const StaticInstPtr _macroStaticInst = NULL)
|
||||
: InstRecord(_when, _thread, _staticInst, _pc, spec,
|
||||
_macroStaticInst)
|
||||
{
|
||||
}
|
||||
|
||||
void traceInst(StaticInstPtr inst, bool ran);
|
||||
|
||||
void dump();
|
||||
virtual void dumpTicks(std::ostream &outs);
|
||||
};
|
||||
|
||||
class ExeTracer : public InstTracer
|
||||
{
|
||||
public:
|
||||
typedef ExeTracerParams Params;
|
||||
ExeTracer(const Params *params) : InstTracer(params)
|
||||
{}
|
||||
|
||||
InstRecord *
|
||||
getInstRecord(Tick when, ThreadContext *tc,
|
||||
const StaticInstPtr staticInst, TheISA::PCState pc,
|
||||
const StaticInstPtr macroStaticInst = NULL)
|
||||
{
|
||||
if (!Debug::ExecEnable)
|
||||
return NULL;
|
||||
|
||||
if (!Trace::enabled)
|
||||
return NULL;
|
||||
|
||||
if (!Debug::ExecSpeculative && tc->misspeculating())
|
||||
return NULL;
|
||||
|
||||
return new ExeTracerRecord(when, tc,
|
||||
staticInst, pc, tc->misspeculating(), macroStaticInst);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#endif // __CPU_EXETRACE_HH__
|
||||
131
simulators/gem5/src/cpu/func_unit.cc
Normal file
131
simulators/gem5/src/cpu/func_unit.cc
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2002-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: Steve Raasch
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The funciton unit
|
||||
//
|
||||
FuncUnit::FuncUnit()
|
||||
{
|
||||
capabilityList.reset();
|
||||
}
|
||||
|
||||
|
||||
// Copy constructor
|
||||
FuncUnit::FuncUnit(const FuncUnit &fu)
|
||||
{
|
||||
|
||||
for (int i = 0; i < Num_OpClasses; ++i) {
|
||||
opLatencies[i] = fu.opLatencies[i];
|
||||
issueLatencies[i] = fu.issueLatencies[i];
|
||||
}
|
||||
|
||||
capabilityList = fu.capabilityList;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FuncUnit::addCapability(OpClass cap, unsigned oplat, unsigned issuelat)
|
||||
{
|
||||
if (issuelat == 0 || oplat == 0)
|
||||
panic("FuncUnit: you don't really want a zero-cycle latency do you?");
|
||||
|
||||
capabilityList.set(cap);
|
||||
|
||||
opLatencies[cap] = oplat;
|
||||
issueLatencies[cap] = issuelat;
|
||||
}
|
||||
|
||||
bool
|
||||
FuncUnit::provides(OpClass capability)
|
||||
{
|
||||
return capabilityList[capability];
|
||||
}
|
||||
|
||||
bitset<Num_OpClasses>
|
||||
FuncUnit::capabilities()
|
||||
{
|
||||
return capabilityList;
|
||||
}
|
||||
|
||||
unsigned &
|
||||
FuncUnit::opLatency(OpClass cap)
|
||||
{
|
||||
return opLatencies[cap];
|
||||
}
|
||||
|
||||
unsigned
|
||||
FuncUnit::issueLatency(OpClass capability)
|
||||
{
|
||||
return issueLatencies[capability];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The SimObjects we use to get the FU information into the simulator
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// We use 2 objects to specify this data in the INI file:
|
||||
// (1) OpDesc - Describes the operation class & latencies
|
||||
// (multiple OpDesc objects can refer to the same
|
||||
// operation classes)
|
||||
// (2) FUDesc - Describes the operations available in the unit &
|
||||
// the number of these units
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// The operation-class description object
|
||||
//
|
||||
OpDesc *
|
||||
OpDescParams::create()
|
||||
{
|
||||
return new OpDesc(this);
|
||||
}
|
||||
|
||||
//
|
||||
// The FuDesc object
|
||||
//
|
||||
FUDesc *
|
||||
FUDescParams::create()
|
||||
{
|
||||
return new FUDesc(this);
|
||||
}
|
||||
106
simulators/gem5/src/cpu/func_unit.hh
Normal file
106
simulators/gem5/src/cpu/func_unit.hh
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2002-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: Steve Raasch
|
||||
*/
|
||||
|
||||
#ifndef __CPU_FUNC_UNIT_HH__
|
||||
#define __CPU_FUNC_UNIT_HH__
|
||||
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/op_class.hh"
|
||||
#include "params/FUDesc.hh"
|
||||
#include "params/OpDesc.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Structures used ONLY during the initialization phase...
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
class OpDesc : public SimObject
|
||||
{
|
||||
public:
|
||||
OpClass opClass;
|
||||
unsigned opLat;
|
||||
unsigned issueLat;
|
||||
|
||||
OpDesc(const OpDescParams *p)
|
||||
: SimObject(p), opClass(p->opClass), opLat(p->opLat),
|
||||
issueLat(p->issueLat) {};
|
||||
};
|
||||
|
||||
class FUDesc : public SimObject
|
||||
{
|
||||
public:
|
||||
std::vector<OpDesc *> opDescList;
|
||||
unsigned number;
|
||||
|
||||
FUDesc(const FUDescParams *p)
|
||||
: SimObject(p), opDescList(p->opList), number(p->count) {};
|
||||
};
|
||||
|
||||
typedef std::vector<OpDesc *>::const_iterator OPDDiterator;
|
||||
typedef std::vector<FUDesc *>::const_iterator FUDDiterator;
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The actual FU object
|
||||
//
|
||||
//
|
||||
//
|
||||
class FuncUnit
|
||||
{
|
||||
private:
|
||||
unsigned opLatencies[Num_OpClasses];
|
||||
unsigned issueLatencies[Num_OpClasses];
|
||||
std::bitset<Num_OpClasses> capabilityList;
|
||||
|
||||
public:
|
||||
FuncUnit();
|
||||
FuncUnit(const FuncUnit &fu);
|
||||
|
||||
std::string name;
|
||||
|
||||
void addCapability(OpClass cap, unsigned oplat, unsigned issuelat);
|
||||
|
||||
bool provides(OpClass capability);
|
||||
std::bitset<Num_OpClasses> capabilities();
|
||||
|
||||
unsigned &opLatency(OpClass capability);
|
||||
unsigned issueLatency(OpClass capability);
|
||||
};
|
||||
|
||||
#endif // __FU_POOL_HH__
|
||||
78
simulators/gem5/src/cpu/inorder/InOrderCPU.py
Normal file
78
simulators/gem5/src/cpu/inorder/InOrderCPU.py
Normal file
@ -0,0 +1,78 @@
|
||||
# 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 BaseCPU import BaseCPU
|
||||
|
||||
class ThreadModel(Enum):
|
||||
vals = ['Single', 'SMT', 'SwitchOnCacheMiss']
|
||||
|
||||
class InOrderCPU(BaseCPU):
|
||||
type = 'InOrderCPU'
|
||||
activity = Param.Unsigned(0, "Initial count")
|
||||
|
||||
threadModel = Param.ThreadModel('SMT', "Multithreading model (SE-MODE only)")
|
||||
|
||||
cachePorts = Param.Unsigned(2, "Cache Ports")
|
||||
stageWidth = Param.Unsigned(4, "Stage width")
|
||||
|
||||
fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)")
|
||||
memBlockSize = Param.Unsigned(64, "Memory Block Size")
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
35
simulators/gem5/src/cpu/inorder/InOrderTrace.py
Normal file
35
simulators/gem5/src/cpu/inorder/InOrderTrace.py
Normal file
@ -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'
|
||||
90
simulators/gem5/src/cpu/inorder/SConscript
Normal file
90
simulators/gem5/src/cpu/inorder/SConscript
Normal file
@ -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')
|
||||
|
||||
DebugFlag('ResReqCount')
|
||||
DebugFlag('InOrderStage')
|
||||
DebugFlag('InOrderStall')
|
||||
DebugFlag('InOrderCPU')
|
||||
DebugFlag('RegDepMap')
|
||||
DebugFlag('InOrderDynInst')
|
||||
DebugFlag('Resource')
|
||||
DebugFlag('InOrderAGEN')
|
||||
DebugFlag('InOrderFetchSeq')
|
||||
DebugFlag('InOrderTLB')
|
||||
DebugFlag('InOrderCachePort')
|
||||
DebugFlag('InOrderBPred')
|
||||
DebugFlag('InOrderDecode')
|
||||
DebugFlag('InOrderExecute')
|
||||
DebugFlag('InOrderInstBuffer')
|
||||
DebugFlag('InOrderUseDef')
|
||||
DebugFlag('InOrderMDU')
|
||||
DebugFlag('InOrderGraduation')
|
||||
DebugFlag('ThreadModel')
|
||||
DebugFlag('RefCount')
|
||||
DebugFlag('AddrDep')
|
||||
DebugFlag('SkedCache')
|
||||
|
||||
CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
|
||||
'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred',
|
||||
'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef',
|
||||
'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource',
|
||||
'InOrderStall','ThreadModel', 'AddrDep'])
|
||||
|
||||
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/fetch_unit.cc')
|
||||
Source('resources/use_def.cc')
|
||||
Source('resources/decode_unit.cc')
|
||||
Source('resources/inst_buffer.cc')
|
||||
Source('resources/graduation_unit.cc')
|
||||
Source('resources/fetch_seq_unit.cc')
|
||||
Source('resources/mult_div_unit.cc')
|
||||
Source('resource_pool.cc')
|
||||
Source('resource_sked.cc')
|
||||
Source('reg_dep_map.cc')
|
||||
Source('thread_state.cc')
|
||||
Source('thread_context.cc')
|
||||
Source('cpu.cc')
|
||||
|
||||
36
simulators/gem5/src/cpu/inorder/SConsopts
Normal file
36
simulators/gem5/src/cpu/inorder/SConsopts
Normal file
@ -0,0 +1,36 @@
|
||||
# -*- 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('*')
|
||||
|
||||
CpuModel('InOrderCPU', 'inorder_cpu_exec.cc',
|
||||
'#include "cpu/inorder/inorder_dyn_inst.hh"',
|
||||
{ 'CPU_exec_context': 'InOrderDynInst' },
|
||||
default=True)
|
||||
85
simulators/gem5/src/cpu/inorder/comm.hh
Normal file
85
simulators/gem5/src/cpu/inorder/comm.hh
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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/isa_traits.hh"
|
||||
#include "base/types.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
|
||||
/** Struct that defines the information passed from in between stages */
|
||||
/** This information mainly goes forward through the pipeline. */
|
||||
struct InterStageStruct {
|
||||
//@todo: probably should make this a list since the amount of
|
||||
// instructions that get passed forward per cycle is
|
||||
// really dependent on issue width, CPI, etc.
|
||||
std::vector<ThePipeline::DynInstPtr> insts;
|
||||
|
||||
// Add any information that needs to be passed forward to stages
|
||||
// below ...
|
||||
};
|
||||
|
||||
/** Struct that defines all backwards communication. */
|
||||
struct TimeStruct {
|
||||
struct StageComm {
|
||||
bool squash;
|
||||
InstSeqNum doneSeqNum;
|
||||
|
||||
bool uncached;
|
||||
ThePipeline::DynInstPtr uncachedLoad;
|
||||
|
||||
StageComm()
|
||||
: squash(false), doneSeqNum(0), uncached(false), uncachedLoad(NULL)
|
||||
{ }
|
||||
};
|
||||
|
||||
StageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads];
|
||||
bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads];
|
||||
bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads];
|
||||
|
||||
TimeStruct()
|
||||
{
|
||||
for (int i = 0; i < ThePipeline::NumStages; i++) {
|
||||
for (int j = 0; j < ThePipeline::MaxThreads; j++) {
|
||||
stageBlock[i][j] = false;
|
||||
stageUnblock[i][j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_COMM_HH__
|
||||
1794
simulators/gem5/src/cpu/inorder/cpu.cc
Normal file
1794
simulators/gem5/src/cpu/inorder/cpu.cc
Normal file
File diff suppressed because it is too large
Load Diff
934
simulators/gem5/src/cpu/inorder/cpu.hh
Normal file
934
simulators/gem5/src/cpu/inorder/cpu.hh
Normal file
@ -0,0 +1,934 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 "arch/registers.hh"
|
||||
#include "arch/types.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "base/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_stage.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "cpu/inorder/thread_state.hh"
|
||||
#include "cpu/o3/dep_graph.hh"
|
||||
#include "cpu/o3/rename_map.hh"
|
||||
#include "cpu/activity.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class CacheUnit;
|
||||
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::RegIndex RegIndex;
|
||||
|
||||
//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);
|
||||
/* Destructor */
|
||||
~InOrderCPU();
|
||||
|
||||
/** Return a reference to the data port. */
|
||||
virtual CpuPort &getDataPort() { return dataPort; }
|
||||
|
||||
/** Return a reference to the instruction port. */
|
||||
virtual CpuPort &getInstPort() { return instPort; }
|
||||
|
||||
/** CPU ID */
|
||||
int cpu_id;
|
||||
|
||||
// SE Mode ASIDs
|
||||
ThreadID asid[ThePipeline::MaxThreads];
|
||||
|
||||
/** Type of core that this is */
|
||||
std::string coreType;
|
||||
|
||||
// Only need for SE MODE
|
||||
enum ThreadModel {
|
||||
Single,
|
||||
SMT,
|
||||
SwitchOnCacheMiss
|
||||
};
|
||||
|
||||
ThreadModel threadModel;
|
||||
|
||||
int readCpuId() { return cpu_id; }
|
||||
|
||||
void setCpuId(int val) { cpu_id = val; }
|
||||
|
||||
Params *cpu_params;
|
||||
|
||||
public:
|
||||
enum Status {
|
||||
Running,
|
||||
Idle,
|
||||
Halted,
|
||||
Blocked,
|
||||
SwitchedOut
|
||||
};
|
||||
|
||||
/** Overall CPU status. */
|
||||
Status _status;
|
||||
private:
|
||||
|
||||
/**
|
||||
* CachePort class for the in-order CPU, interacting with a
|
||||
* specific CacheUnit in the pipeline.
|
||||
*/
|
||||
class CachePort : public CpuPort
|
||||
{
|
||||
|
||||
private:
|
||||
/** Pointer to cache unit */
|
||||
CacheUnit *cacheUnit;
|
||||
|
||||
public:
|
||||
/** Default constructor. */
|
||||
CachePort(CacheUnit *_cacheUnit);
|
||||
|
||||
protected:
|
||||
|
||||
/** Timing version of receive */
|
||||
bool recvTimingResp(PacketPtr pkt);
|
||||
|
||||
/** Handles doing a retry of a failed timing request. */
|
||||
void recvRetry();
|
||||
|
||||
/** Ignoring snoops for now. */
|
||||
void recvTimingSnoopReq(PacketPtr pkt) { }
|
||||
};
|
||||
|
||||
/** 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() const;
|
||||
};
|
||||
|
||||
/** The tick event used for scheduling CPU ticks. */
|
||||
TickEvent tickEvent;
|
||||
|
||||
/** Schedule tick event, regardless of its current state. */
|
||||
void scheduleTickEvent(int delay)
|
||||
{
|
||||
assert(!tickEvent.scheduled() || tickEvent.squashed());
|
||||
reschedule(&tickEvent, nextCycle(curTick() + ticks(delay)), true);
|
||||
}
|
||||
|
||||
/** 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,
|
||||
ActivateNextReadyThread,
|
||||
DeactivateThread,
|
||||
HaltThread,
|
||||
SuspendThread,
|
||||
Trap,
|
||||
Syscall,
|
||||
SquashFromMemStall,
|
||||
UpdatePCs,
|
||||
NumCPUEvents
|
||||
};
|
||||
|
||||
static std::string eventNames[NumCPUEvents];
|
||||
|
||||
enum CPUEventPri {
|
||||
InOrderCPU_Pri = Event::CPU_Tick_Pri,
|
||||
Syscall_Pri = Event::CPU_Tick_Pri + 9,
|
||||
ActivateNextReadyThread_Pri = Event::CPU_Tick_Pri + 10
|
||||
};
|
||||
|
||||
/** Define CPU Event */
|
||||
class CPUEvent : public Event
|
||||
{
|
||||
protected:
|
||||
InOrderCPU *cpu;
|
||||
|
||||
public:
|
||||
CPUEventType cpuEventType;
|
||||
ThreadID tid;
|
||||
DynInstPtr inst;
|
||||
Fault fault;
|
||||
unsigned vpe;
|
||||
short syscall_num;
|
||||
|
||||
public:
|
||||
/** Constructs a CPU event. */
|
||||
CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault,
|
||||
ThreadID _tid, DynInstPtr inst, CPUEventPri event_pri);
|
||||
|
||||
/** Set Type of Event To Be Scheduled */
|
||||
void setEvent(CPUEventType e_type, Fault _fault, ThreadID _tid,
|
||||
DynInstPtr _inst)
|
||||
{
|
||||
fault = _fault;
|
||||
cpuEventType = e_type;
|
||||
tid = _tid;
|
||||
inst = _inst;
|
||||
vpe = 0;
|
||||
}
|
||||
|
||||
/** Processes a CPU event. */
|
||||
void process();
|
||||
|
||||
/** Returns the description of the CPU event. */
|
||||
const char *description() const;
|
||||
|
||||
/** Schedule Event */
|
||||
void scheduleEvent(int delay);
|
||||
|
||||
/** Unschedule This Event */
|
||||
void unscheduleEvent();
|
||||
};
|
||||
|
||||
/** Schedule a CPU Event */
|
||||
void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, ThreadID tid,
|
||||
DynInstPtr inst, unsigned delay = 0,
|
||||
CPUEventPri event_pri = InOrderCPU_Pri);
|
||||
|
||||
public:
|
||||
|
||||
/** Width (processing bandwidth) of each stage */
|
||||
int stageWidth;
|
||||
|
||||
/** Interface between the CPU and CPU resources. */
|
||||
ResourcePool *resPool;
|
||||
|
||||
/** Instruction used to signify that there is no *real* instruction in
|
||||
buffer slot */
|
||||
DynInstPtr dummyInst[ThePipeline::MaxThreads];
|
||||
DynInstPtr dummyBufferInst;
|
||||
DynInstPtr dummyReqInst;
|
||||
DynInstPtr dummyTrapInst[ThePipeline::MaxThreads];
|
||||
|
||||
/** Used by resources to signify a denied access to a resource. */
|
||||
ResourceRequest *dummyReq[ThePipeline::MaxThreads];
|
||||
|
||||
/** The Pipeline Stages for the CPU */
|
||||
PipelineStage *pipelineStage[ThePipeline::NumStages];
|
||||
|
||||
/** Program Counters */
|
||||
TheISA::PCState pc[ThePipeline::MaxThreads];
|
||||
|
||||
/** Last Committed PC */
|
||||
TheISA::PCState lastCommittedPC[ThePipeline::MaxThreads];
|
||||
|
||||
/** The Register File for the CPU */
|
||||
union {
|
||||
FloatReg f[ThePipeline::MaxThreads][TheISA::NumFloatRegs];
|
||||
FloatRegBits i[ThePipeline::MaxThreads][TheISA::NumFloatRegs];
|
||||
} floatRegs;
|
||||
TheISA::IntReg intRegs[ThePipeline::MaxThreads][TheISA::NumIntRegs];
|
||||
|
||||
/** ISA state */
|
||||
TheISA::ISA isa[ThePipeline::MaxThreads];
|
||||
|
||||
/** Dependency Tracker for Integer & Floating Point Regs */
|
||||
RegDepMap archRegDepMap[ThePipeline::MaxThreads];
|
||||
|
||||
/** Register Types Used in Dependency Tracking */
|
||||
enum RegType { IntType, FloatType, MiscType, NumRegTypes};
|
||||
|
||||
/** Global communication structure */
|
||||
TimeBuffer<TimeStruct> timeBuffer;
|
||||
|
||||
/** Communication structure that sits in between pipeline stages */
|
||||
StageQueue *stageQueue[ThePipeline::NumStages-1];
|
||||
|
||||
TheISA::TLB *getITBPtr();
|
||||
TheISA::TLB *getDTBPtr();
|
||||
|
||||
TheISA::Decoder *getDecoderPtr(unsigned tid);
|
||||
|
||||
/** Accessor Type for the SkedCache */
|
||||
typedef uint32_t SkedID;
|
||||
|
||||
/** Cache of Instruction Schedule using the instruction's name as a key */
|
||||
static m5::hash_map<SkedID, ThePipeline::RSkedPtr> skedCache;
|
||||
|
||||
typedef m5::hash_map<SkedID, ThePipeline::RSkedPtr>::iterator SkedCacheIt;
|
||||
|
||||
/** Initialized to last iterator in map, signifying a invalid entry
|
||||
on map searches
|
||||
*/
|
||||
SkedCacheIt endOfSkedIt;
|
||||
|
||||
ThePipeline::RSkedPtr frontEndSked;
|
||||
ThePipeline::RSkedPtr faultSked;
|
||||
|
||||
/** Add a new instruction schedule to the schedule cache */
|
||||
void addToSkedCache(DynInstPtr inst, ThePipeline::RSkedPtr inst_sked)
|
||||
{
|
||||
SkedID sked_id = genSkedID(inst);
|
||||
assert(skedCache.find(sked_id) == skedCache.end());
|
||||
skedCache[sked_id] = inst_sked;
|
||||
}
|
||||
|
||||
|
||||
/** Find a instruction schedule */
|
||||
ThePipeline::RSkedPtr lookupSked(DynInstPtr inst)
|
||||
{
|
||||
SkedID sked_id = genSkedID(inst);
|
||||
SkedCacheIt lookup_it = skedCache.find(sked_id);
|
||||
|
||||
if (lookup_it != endOfSkedIt) {
|
||||
return (*lookup_it).second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t INST_OPCLASS = 26;
|
||||
static const uint8_t INST_LOAD = 25;
|
||||
static const uint8_t INST_STORE = 24;
|
||||
static const uint8_t INST_CONTROL = 23;
|
||||
static const uint8_t INST_NONSPEC = 22;
|
||||
static const uint8_t INST_DEST_REGS = 18;
|
||||
static const uint8_t INST_SRC_REGS = 14;
|
||||
static const uint8_t INST_SPLIT_DATA = 13;
|
||||
|
||||
inline SkedID genSkedID(DynInstPtr inst)
|
||||
{
|
||||
SkedID id = 0;
|
||||
id = (inst->opClass() << INST_OPCLASS) |
|
||||
(inst->isLoad() << INST_LOAD) |
|
||||
(inst->isStore() << INST_STORE) |
|
||||
(inst->isControl() << INST_CONTROL) |
|
||||
(inst->isNonSpeculative() << INST_NONSPEC) |
|
||||
(inst->numDestRegs() << INST_DEST_REGS) |
|
||||
(inst->numSrcRegs() << INST_SRC_REGS) |
|
||||
(inst->splitInst << INST_SPLIT_DATA);
|
||||
return id;
|
||||
}
|
||||
|
||||
ThePipeline::RSkedPtr createFrontEndSked();
|
||||
ThePipeline::RSkedPtr createFaultSked();
|
||||
ThePipeline::RSkedPtr createBackEndSked(DynInstPtr inst);
|
||||
|
||||
class StageScheduler {
|
||||
private:
|
||||
ThePipeline::RSkedPtr rsked;
|
||||
int stageNum;
|
||||
int nextTaskPriority;
|
||||
|
||||
public:
|
||||
StageScheduler(ThePipeline::RSkedPtr _rsked, int stage_num)
|
||||
: rsked(_rsked), stageNum(stage_num),
|
||||
nextTaskPriority(0)
|
||||
{ }
|
||||
|
||||
void needs(int unit, int request) {
|
||||
rsked->push(new ScheduleEntry(
|
||||
stageNum, nextTaskPriority++, unit, request
|
||||
));
|
||||
}
|
||||
|
||||
void needs(int unit, int request, int param) {
|
||||
rsked->push(new ScheduleEntry(
|
||||
stageNum, nextTaskPriority++, unit, request, param
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/** Data port. Note that it has to appear after the resPool. */
|
||||
CachePort dataPort;
|
||||
|
||||
/** Instruction port. Note that it has to appear after the resPool. */
|
||||
CachePort instPort;
|
||||
|
||||
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();
|
||||
|
||||
/** HW return from error interrupt. */
|
||||
Fault hwrei(ThreadID tid);
|
||||
|
||||
bool simPalCheck(int palFunc, ThreadID tid);
|
||||
|
||||
void checkForInterrupts();
|
||||
|
||||
/** 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"); }
|
||||
|
||||
/** Check if this address is a valid instruction address. */
|
||||
bool validInstAddr(Addr addr) { return true; }
|
||||
|
||||
/** Check if this address is a valid data address. */
|
||||
bool validDataAddr(Addr addr) { return true; }
|
||||
|
||||
/** Schedule a syscall on the CPU */
|
||||
void syscallContext(Fault fault, ThreadID tid, DynInstPtr inst,
|
||||
int delay = 0);
|
||||
|
||||
/** Executes a syscall.*/
|
||||
void syscall(int64_t callnum, ThreadID tid);
|
||||
|
||||
/** Schedule a trap on the CPU */
|
||||
void trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0);
|
||||
|
||||
/** Perform trap to Handle Given Fault */
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
/** Schedule thread activation on the CPU */
|
||||
void activateContext(ThreadID tid, int delay = 0);
|
||||
|
||||
/** Add Thread to Active Threads List. */
|
||||
void activateThread(ThreadID tid);
|
||||
|
||||
/** Activate Thread In Each Pipeline Stage */
|
||||
void activateThreadInPipeline(ThreadID tid);
|
||||
|
||||
/** Schedule Thread Activation from Ready List */
|
||||
void activateNextReadyContext(int delay = 0);
|
||||
|
||||
/** Add Thread From Ready List to Active Threads List. */
|
||||
void activateNextReadyThread();
|
||||
|
||||
/** Schedule a thread deactivation on the CPU */
|
||||
void deactivateContext(ThreadID tid, int delay = 0);
|
||||
|
||||
/** Remove from Active Thread List */
|
||||
void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Schedule a thread suspension on the CPU */
|
||||
void suspendContext(ThreadID tid);
|
||||
|
||||
/** Suspend Thread, Remove from Active Threads List, Add to Suspend List */
|
||||
void suspendThread(ThreadID tid);
|
||||
|
||||
/** Schedule a thread halt on the CPU */
|
||||
void haltContext(ThreadID tid);
|
||||
|
||||
/** Halt Thread, Remove from Active Thread List, Place Thread on Halted
|
||||
* Threads List
|
||||
*/
|
||||
void haltThread(ThreadID tid);
|
||||
|
||||
/** squashFromMemStall() - sets up a squash event
|
||||
* squashDueToMemStall() - squashes pipeline
|
||||
* @note: maybe squashContext/squashThread would be better?
|
||||
*/
|
||||
void squashFromMemStall(DynInstPtr inst, ThreadID tid, int delay = 0);
|
||||
void squashDueToMemStall(int stage_num, InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
void removePipelineStalls(ThreadID tid);
|
||||
void squashThreadInPipeline(ThreadID tid);
|
||||
void squashBehindMemStall(int stage_num, InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
PipelineStage* getPipeStage(int stage_num);
|
||||
|
||||
int
|
||||
contextId()
|
||||
{
|
||||
hack_once("return a bogus context id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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(ThreadID tid)
|
||||
{ return globalSeqNum[tid]++; }
|
||||
|
||||
/** Get the current instruction sequence number, and increment it. */
|
||||
InstSeqNum nextInstSeqNum(ThreadID tid)
|
||||
{ return globalSeqNum[tid]; }
|
||||
|
||||
/** Increment Instruction Sequence Number */
|
||||
void incrInstSeqNum(ThreadID tid)
|
||||
{ globalSeqNum[tid]++; }
|
||||
|
||||
/** Set Instruction Sequence Number */
|
||||
void setInstSeqNum(ThreadID tid, InstSeqNum seq_num)
|
||||
{
|
||||
globalSeqNum[tid] = seq_num;
|
||||
}
|
||||
|
||||
/** Get & Update Next Event Number */
|
||||
InstSeqNum getNextEventNum()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
return cpuEventNum++;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Register file accessors */
|
||||
uint64_t readIntReg(RegIndex reg_idx, ThreadID tid);
|
||||
|
||||
FloatReg readFloatReg(RegIndex reg_idx, ThreadID tid);
|
||||
|
||||
FloatRegBits readFloatRegBits(RegIndex reg_idx, ThreadID tid);
|
||||
|
||||
void setIntReg(RegIndex reg_idx, uint64_t val, ThreadID tid);
|
||||
|
||||
void setFloatReg(RegIndex reg_idx, FloatReg val, ThreadID tid);
|
||||
|
||||
void setFloatRegBits(RegIndex reg_idx, FloatRegBits val, ThreadID tid);
|
||||
|
||||
RegType inline getRegType(RegIndex reg_idx)
|
||||
{
|
||||
if (reg_idx < TheISA::FP_Base_DepTag)
|
||||
return IntType;
|
||||
else if (reg_idx < TheISA::Ctrl_Base_DepTag)
|
||||
return FloatType;
|
||||
else
|
||||
return MiscType;
|
||||
}
|
||||
|
||||
RegIndex flattenRegIdx(RegIndex reg_idx, RegType ®_type, ThreadID tid);
|
||||
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscRegNoEffect(int misc_reg, ThreadID tid = 0);
|
||||
|
||||
/** Reads a misc. register, including any side effects the read
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
MiscReg readMiscReg(int misc_reg, ThreadID tid = 0);
|
||||
|
||||
/** Sets a miscellaneous register. */
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val,
|
||||
ThreadID 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, ThreadID tid = 0);
|
||||
|
||||
/** Reads a int/fp/misc reg. from another thread depending on ISA-defined
|
||||
* target thread
|
||||
*/
|
||||
uint64_t readRegOtherThread(unsigned misc_reg,
|
||||
ThreadID tid = InvalidThreadID);
|
||||
|
||||
/** Sets a int/fp/misc reg. from another thread depending on an ISA-defined
|
||||
* target thread
|
||||
*/
|
||||
void setRegOtherThread(unsigned misc_reg, const MiscReg &val,
|
||||
ThreadID tid);
|
||||
|
||||
/** Reads the commit PC of a specific thread. */
|
||||
TheISA::PCState
|
||||
pcState(ThreadID tid)
|
||||
{
|
||||
return pc[tid];
|
||||
}
|
||||
|
||||
/** Sets the commit PC of a specific thread. */
|
||||
void
|
||||
pcState(const TheISA::PCState &newPC, ThreadID tid)
|
||||
{
|
||||
pc[tid] = newPC;
|
||||
}
|
||||
|
||||
Addr instAddr(ThreadID tid) { return pc[tid].instAddr(); }
|
||||
Addr nextInstAddr(ThreadID tid) { return pc[tid].nextInstAddr(); }
|
||||
MicroPC microPC(ThreadID tid) { return pc[tid].microPC(); }
|
||||
|
||||
/** Function to add instruction onto the head of the list of the
|
||||
* instructions. Used when new instructions are fetched.
|
||||
*/
|
||||
ListIt addInst(DynInstPtr inst);
|
||||
|
||||
/** Find instruction on instruction list */
|
||||
ListIt findInst(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Function to tell the CPU that an instruction has completed. */
|
||||
void instDone(DynInstPtr inst, ThreadID 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,ThreadID tid);
|
||||
|
||||
/** Removes the instruction pointed to by the iterator. */
|
||||
inline void squashInstIt(const ListIt inst_it, ThreadID tid);
|
||||
|
||||
/** Cleans up all instructions on the instruction remove list. */
|
||||
void cleanUpRemovedInsts();
|
||||
|
||||
/** Cleans up all events 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, Addr addr,
|
||||
uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
/** Forwards an instruction write. to the appropriate data
|
||||
* resource (indexes into Resource Pool thru "dataPortIdx")
|
||||
*/
|
||||
Fault write(DynInstPtr inst, uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *write_res = NULL);
|
||||
|
||||
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;
|
||||
|
||||
bool trapPending[ThePipeline::MaxThreads];
|
||||
|
||||
/** 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<ThreadID> fetchPriorityList;
|
||||
|
||||
protected:
|
||||
/** Active Threads List */
|
||||
std::list<ThreadID> activeThreads;
|
||||
|
||||
/** Ready Threads List */
|
||||
std::list<ThreadID> readyThreads;
|
||||
|
||||
/** Suspended Threads List */
|
||||
std::list<ThreadID> suspendedThreads;
|
||||
|
||||
/** Halted Threads List */
|
||||
std::list<ThreadID> haltedThreads;
|
||||
|
||||
/** Thread Status Functions */
|
||||
bool isThreadActive(ThreadID tid);
|
||||
bool isThreadReady(ThreadID tid);
|
||||
bool isThreadSuspended(ThreadID 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:
|
||||
/** Number of Active Threads in the CPU */
|
||||
ThreadID numActiveThreads() { return activeThreads.size(); }
|
||||
|
||||
/** Thread id of active thread
|
||||
* Only used for SwitchOnCacheMiss model.
|
||||
* Assumes only 1 thread active
|
||||
*/
|
||||
ThreadID activeThreadId()
|
||||
{
|
||||
if (numActiveThreads() > 0)
|
||||
return activeThreads.front();
|
||||
else
|
||||
return InvalidThreadID;
|
||||
}
|
||||
|
||||
|
||||
/** 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();
|
||||
|
||||
virtual void wakeup();
|
||||
|
||||
/* 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(ThreadID tid = 0)
|
||||
{
|
||||
return thread[tid]->getTC();
|
||||
}
|
||||
|
||||
/** Count the Total Instructions Committed in the CPU. */
|
||||
virtual Counter totalInsts() const
|
||||
{
|
||||
Counter total(0);
|
||||
|
||||
for (ThreadID tid = 0; tid < (ThreadID)thread.size(); tid++)
|
||||
total += thread[tid]->numInst;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Count the Total Ops Committed in the CPU. */
|
||||
virtual Counter totalOps() const
|
||||
{
|
||||
Counter total(0);
|
||||
|
||||
for (ThreadID tid = 0; tid < (ThreadID)thread.size(); tid++)
|
||||
total += thread[tid]->numOp;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Pointer to the system. */
|
||||
System *system;
|
||||
|
||||
/** The global sequence number counter. */
|
||||
InstSeqNum globalSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
#ifdef DEBUG
|
||||
/** The global event number counter. */
|
||||
InstSeqNum cpuEventNum;
|
||||
|
||||
/** Number of resource requests active in CPU **/
|
||||
unsigned resReqCount;
|
||||
#endif
|
||||
|
||||
Addr lockAddr;
|
||||
|
||||
/** Temporary fix for the lock flag, works in the UP case. */
|
||||
bool lockFlag;
|
||||
|
||||
/** Counter of how many stages have completed draining */
|
||||
int drainCount;
|
||||
|
||||
/** Pointers to all of the threads in the CPU. */
|
||||
std::vector<Thread *> thread;
|
||||
|
||||
/** Whether or not the CPU should defer its registration. */
|
||||
bool deferRegistration;
|
||||
|
||||
/** Per-Stage Instruction Tracing */
|
||||
bool stageTracing;
|
||||
|
||||
/** The cycle that the CPU was last running, used for statistics. */
|
||||
Tick lastRunningCycle;
|
||||
|
||||
void updateContextSwitchStats();
|
||||
unsigned instsPerSwitch;
|
||||
Stats::Average instsPerCtxtSwitch;
|
||||
Stats::Scalar numCtxtSwitches;
|
||||
|
||||
/** 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 or no
|
||||
* stages active.
|
||||
*/
|
||||
Stats::Scalar idleCycles;
|
||||
|
||||
/** Stat for total number of cycles the CPU is active. */
|
||||
Stats::Scalar runCycles;
|
||||
|
||||
/** Percentage of cycles a stage was active */
|
||||
Stats::Formula activity;
|
||||
|
||||
/** Instruction Mix Stats */
|
||||
Stats::Scalar comLoads;
|
||||
Stats::Scalar comStores;
|
||||
Stats::Scalar comBranches;
|
||||
Stats::Scalar comNops;
|
||||
Stats::Scalar comNonSpec;
|
||||
Stats::Scalar comInts;
|
||||
Stats::Scalar comFloats;
|
||||
|
||||
/** Stat for the number of committed instructions per thread. */
|
||||
Stats::Vector committedInsts;
|
||||
|
||||
/** Stat for the number of committed ops per thread. */
|
||||
Stats::Vector committedOps;
|
||||
|
||||
/** 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__
|
||||
279
simulators/gem5/src/cpu/inorder/first_stage.cc
Normal file
279
simulators/gem5/src/cpu/inorder/first_stage.cc
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/InOrderStage.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(ThreadID 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, ThreadID 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 (!skidBuffer[tid].empty()) {
|
||||
if (skidBuffer[tid].front()->seqNum <= squash_seq_num) {
|
||||
DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because "
|
||||
"it's <= squashing seqNum %i.\n",
|
||||
tid,
|
||||
skidBuffer[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,
|
||||
skidBuffer[tid].size());
|
||||
break;
|
||||
}
|
||||
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] "
|
||||
"PC %s.\n", tid, skidBuffer[tid].front()->seqNum,
|
||||
skidBuffer[tid].front()->pc);
|
||||
skidBuffer[tid].pop_front();
|
||||
}
|
||||
|
||||
// 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::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
// Need to preserve the stalling instruction in first-stage
|
||||
// since the squash() from first stage also removes
|
||||
// the instruction from the CPU (removeInstsUntil). If that
|
||||
// functionality gets changed then you can move this offset.
|
||||
// (stalling instruction = seq_num + 1)
|
||||
squash(seq_num+1, tid);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FirstStage::processStage(bool &status_change)
|
||||
{
|
||||
list<ThreadID>::iterator threads = activeThreads->begin();
|
||||
|
||||
//Check stall and squash signals.
|
||||
while (threads != activeThreads->end()) {
|
||||
ThreadID tid = *threads++;
|
||||
status_change = checkSignalsAndUpdate(tid) || status_change;
|
||||
}
|
||||
|
||||
while (instsProcessed < stageWidth) {
|
||||
ThreadID tid = getFetchingThread(fetchPolicy);
|
||||
|
||||
if (tid >= 0) {
|
||||
DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
|
||||
processThread(status_change, tid);
|
||||
DPRINTF(InOrderStage, "Done Processing [tid:%i]\n",tid);
|
||||
} else {
|
||||
DPRINTF(InOrderStage, "No more threads to fetch from.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (instsProcessed > 0) {
|
||||
++runCycles;
|
||||
idle = false;
|
||||
} else {
|
||||
++idleCycles;
|
||||
idle = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@TODO: Note in documentation, that when you make a pipeline stage change,
|
||||
//then make sure you change the first stage too
|
||||
void
|
||||
FirstStage::processInsts(ThreadID tid)
|
||||
{
|
||||
bool all_reqs_completed = true;
|
||||
|
||||
for (int insts_fetched = instsProcessed;
|
||||
insts_fetched < stageWidth;
|
||||
insts_fetched++) {
|
||||
|
||||
DynInstPtr inst;
|
||||
bool new_inst = false;
|
||||
|
||||
if (!skidBuffer[tid].empty()) {
|
||||
inst = skidBuffer[tid].front();
|
||||
} else {
|
||||
// Get new instruction.
|
||||
new_inst = true;
|
||||
|
||||
inst = new InOrderDynInst(cpu,
|
||||
cpu->thread[tid],
|
||||
cpu->nextInstSeqNum(tid),
|
||||
tid,
|
||||
tid);
|
||||
|
||||
#if TRACING_ON
|
||||
inst->traceData =
|
||||
tracer->getInstRecord(ThePipeline::NumStages,
|
||||
cpu->stageTracing,
|
||||
cpu->thread[tid]->getTC());
|
||||
|
||||
#else
|
||||
inst->traceData = NULL;
|
||||
#endif // TRACING_ON
|
||||
|
||||
// Add instruction to the CPU's list of instructions.
|
||||
inst->setInstListIt(cpu->addInst(inst));
|
||||
|
||||
// Create Front-End Resource Schedule For Instruction
|
||||
inst->setFrontSked(cpu->frontEndSked);
|
||||
}
|
||||
|
||||
int reqs_processed = 0;
|
||||
all_reqs_completed = processInstSchedule(inst, reqs_processed);
|
||||
|
||||
// If the instruction isnt squashed & we've completed one request
|
||||
// Then we can officially count this instruction toward the stage's
|
||||
// bandwidth count
|
||||
if (reqs_processed > 0)
|
||||
instsProcessed++;
|
||||
|
||||
if (!all_reqs_completed || !sendInstToNextStage(inst)) {
|
||||
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);
|
||||
skidBuffer[tid].push_back(inst);
|
||||
}
|
||||
block(tid);
|
||||
break;
|
||||
} else if (!skidBuffer[tid].empty()){
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Finished all "
|
||||
"requests for this stage.\n", tid, inst->seqNum);
|
||||
skidBuffer[tid].pop_front();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Record that stage has written to the time buffer for activity
|
||||
// tracking.
|
||||
if (instsProcessed) {
|
||||
wroteToTimeBuffer = true;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadID
|
||||
FirstStage::getFetchingThread(FetchPriority &fetch_priority)
|
||||
{
|
||||
ThreadID num_active_threads = cpu->numActiveThreads();
|
||||
|
||||
if (num_active_threads > 1) {
|
||||
switch (fetch_priority) {
|
||||
case SingleThread:
|
||||
return cpu->activeThreadId();
|
||||
|
||||
case RoundRobin:
|
||||
return roundRobin();
|
||||
|
||||
default:
|
||||
return InvalidThreadID;
|
||||
}
|
||||
} else if (num_active_threads == 1) {
|
||||
ThreadID tid = *activeThreads->begin();
|
||||
|
||||
if (stageStatus[tid] == Running ||
|
||||
stageStatus[tid] == Idle ||
|
||||
stageStatus[tid] == Unblocking) {
|
||||
return tid;
|
||||
} else {
|
||||
return InvalidThreadID;
|
||||
}
|
||||
} else {
|
||||
return InvalidThreadID;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadID
|
||||
FirstStage::roundRobin()
|
||||
{
|
||||
list<ThreadID>::iterator pri_iter = fetchPriorityList->begin();
|
||||
list<ThreadID>::iterator end = fetchPriorityList->end();
|
||||
|
||||
ThreadID high_pri;
|
||||
|
||||
while (pri_iter != end) {
|
||||
high_pri = *pri_iter;
|
||||
|
||||
assert(high_pri <= numThreads);
|
||||
|
||||
if (stageStatus[high_pri] == Running ||
|
||||
stageStatus[high_pri] == Idle ||
|
||||
stageStatus[high_pri] == Unblocking){
|
||||
|
||||
fetchPriorityList->erase(pri_iter);
|
||||
fetchPriorityList->push_back(high_pri);
|
||||
|
||||
return high_pri;
|
||||
}
|
||||
|
||||
pri_iter++;
|
||||
}
|
||||
|
||||
return InvalidThreadID;
|
||||
}
|
||||
94
simulators/gem5/src/cpu/inorder/first_stage.hh
Normal file
94
simulators/gem5/src/cpu/inorder/first_stage.hh
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 "cpu/inorder/comm.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/params.hh"
|
||||
#include "cpu/inorder/pipeline_stage.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/timebuf.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(ThreadID tid);
|
||||
|
||||
/** Squash Instructions Above a Seq. Num */
|
||||
void squash(InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** There are no insts. coming from previous stages, so there is
|
||||
* no need to sort insts here
|
||||
*/
|
||||
void sortInsts() {}
|
||||
|
||||
/** 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<ThreadID> *fetchPriorityList;
|
||||
|
||||
/** Return the next fetching thread */
|
||||
ThreadID getFetchingThread(FetchPriority &fetch_priority);
|
||||
|
||||
/** Return next thread given Round Robin Policy for Thread Fetching */
|
||||
ThreadID roundRobin();
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_FIRST_STAGE_HH__
|
||||
67
simulators/gem5/src/cpu/inorder/inorder_cpu_builder.cc
Normal file
67
simulators/gem5/src/cpu/inorder/inorder_cpu_builder.cc
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
InOrderCPU *
|
||||
InOrderCPUParams::create()
|
||||
{
|
||||
ThreadID actual_num_threads;
|
||||
if (FullSystem) {
|
||||
// Full-system only supports a single thread for the moment.
|
||||
actual_num_threads = 1;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
593
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.cc
Normal file
593
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.cc
Normal file
@ -0,0 +1,593 @@
|
||||
/*
|
||||
* 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 <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "base/bigint.hh"
|
||||
#include "base/cp_annotate.hh"
|
||||
#include "base/cprintf.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/InOrderDynInst.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/fault_fwd.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
using namespace ThePipeline;
|
||||
|
||||
InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
|
||||
InOrderThreadState *state,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID tid,
|
||||
unsigned _asid)
|
||||
: seqNum(seq_num), squashSeqNum(0), threadNumber(tid), asid(_asid),
|
||||
virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu),
|
||||
thread(state), fault(NoFault), memData(NULL), loadData(0),
|
||||
storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
|
||||
readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
|
||||
memTime(0), splitMemData(NULL), splitMemReq(NULL), totalSize(0),
|
||||
split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
|
||||
split2ndDataPtr(NULL), split2ndFlags(0), splitInst(false),
|
||||
splitFinishCnt(0), split2ndStoreDataPtr(NULL), splitInstSked(false),
|
||||
inFrontEnd(true), frontSked(NULL), backSked(NULL),
|
||||
squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
|
||||
fetchMemReq(NULL), dataMemReq(NULL), instEffAddr(0), eaCalcDone(false),
|
||||
lqIdx(0), sqIdx(0), onInstList(false)
|
||||
{
|
||||
for(int i = 0; i < MaxInstSrcRegs; i++) {
|
||||
_readySrcRegIdx[i] = false;
|
||||
_srcRegIdx[i] = 0;
|
||||
}
|
||||
|
||||
for(int j = 0; j < MaxInstDestRegs; j++) {
|
||||
_destRegIdx[j] = 0;
|
||||
_prevDestRegIdx[j] = 0;
|
||||
}
|
||||
|
||||
++instcount;
|
||||
DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created."
|
||||
" (active insts: %i)\n", threadNumber, seqNum, instcount);
|
||||
|
||||
}
|
||||
|
||||
int InOrderDynInst::instcount = 0;
|
||||
|
||||
int
|
||||
InOrderDynInst::cpuId()
|
||||
{
|
||||
return cpu->cpuId();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::setStaticInst(StaticInstPtr si)
|
||||
{
|
||||
staticInst = si;
|
||||
|
||||
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()
|
||||
{
|
||||
inFrontEnd = true;
|
||||
|
||||
fetchMemReq = NULL;
|
||||
dataMemReq = NULL;
|
||||
splitMemData = NULL;
|
||||
split2ndAddr = 0;
|
||||
split2ndAccess = false;
|
||||
splitInst = false;
|
||||
splitInstSked = false;
|
||||
splitFinishCnt = 0;
|
||||
|
||||
effAddr = 0;
|
||||
physEffAddr = 0;
|
||||
|
||||
readyRegs = 0;
|
||||
|
||||
nextStage = 0;
|
||||
|
||||
status.reset();
|
||||
|
||||
memAddrReady = false;
|
||||
eaCalcDone = 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
|
||||
if (instcount > 100) {
|
||||
fatal("Number of Active Instructions in CPU is too high. "
|
||||
"(Not Dereferencing Ptrs. Correctly?)\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::resetInstCount()
|
||||
{
|
||||
instcount = 0;
|
||||
}
|
||||
|
||||
|
||||
InOrderDynInst::~InOrderDynInst()
|
||||
{
|
||||
if (traceData)
|
||||
delete traceData;
|
||||
|
||||
if (splitMemData)
|
||||
delete [] splitMemData;
|
||||
|
||||
fault = NoFault;
|
||||
|
||||
--instcount;
|
||||
|
||||
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::calcEA()
|
||||
{
|
||||
this->fault = this->staticInst->eaComp(this, this->traceData);
|
||||
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;
|
||||
}
|
||||
|
||||
Fault
|
||||
InOrderDynInst::memAccess()
|
||||
{
|
||||
return initiateAcc();
|
||||
}
|
||||
|
||||
|
||||
Fault
|
||||
InOrderDynInst::hwrei()
|
||||
{
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
// Can only do a hwrei when in pal mode.
|
||||
if (!(this->instAddr() & 0x3))
|
||||
return new AlphaISA::UnimplementedOpcodeFault;
|
||||
|
||||
// Set the next PC based on the value of the EXC_ADDR IPR.
|
||||
AlphaISA::PCState pc = this->pcState();
|
||||
pc.npc(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
|
||||
this->threadNumber));
|
||||
this->pcState(pc);
|
||||
if (CPA::available()) {
|
||||
ThreadContext *tc = this->cpu->tcBase(this->threadNumber);
|
||||
CPA::cpa()->swAutoBegin(tc, this->nextInstAddr());
|
||||
}
|
||||
|
||||
// Tell CPU to clear any state it needs to if a hwrei is taken.
|
||||
this->cpu->hwrei(this->threadNumber);
|
||||
#endif
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderDynInst::trap(Fault fault)
|
||||
{
|
||||
this->cpu->trap(fault, this->threadNumber, this);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InOrderDynInst::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);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::syscall(int64_t callnum)
|
||||
{
|
||||
if (FullSystem)
|
||||
panic("Syscall emulation isn't available in FS mode.\n");
|
||||
|
||||
syscallNum = callnum;
|
||||
cpu->syscallContext(NoFault, this->threadNumber, this);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::setSquashInfo(unsigned stage_num)
|
||||
{
|
||||
squashingStage = stage_num;
|
||||
|
||||
// If it's a fault, then we need to squash
|
||||
// the faulting instruction too. Squash
|
||||
// functions squash above a seqNum, so we
|
||||
// decrement here for that case
|
||||
if (fault != NoFault) {
|
||||
squashSeqNum = seqNum - 1;
|
||||
return;
|
||||
} else
|
||||
squashSeqNum = seqNum;
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (staticInst && isControl()) {
|
||||
TheISA::PCState nextPC = pc;
|
||||
TheISA::advancePC(nextPC, staticInst);
|
||||
|
||||
// Check to see if we should squash after the
|
||||
// branch or after a branch delay slot.
|
||||
if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
|
||||
squashSeqNum = seqNum + 1;
|
||||
else
|
||||
squashSeqNum = seqNum;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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] [src:%i] Int being set "
|
||||
"to %#x.\n", threadNumber, seqNum, idx, val);
|
||||
instSrc[idx].intVal = val;
|
||||
}
|
||||
|
||||
/** Records an fp register being set to a value. */
|
||||
void
|
||||
InOrderDynInst::setFloatSrc(int idx, FloatReg val)
|
||||
{
|
||||
instSrc[idx].fpVal.f = val;
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FP being set "
|
||||
"to %x, %08f...%08f\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
|
||||
}
|
||||
|
||||
/** Records an fp register being set to an integer value. */
|
||||
void
|
||||
InOrderDynInst::setFloatRegBitsSrc(int idx, FloatRegBits val)
|
||||
{
|
||||
instSrc[idx].fpVal.i = val;
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
|
||||
"to %x, %08f...%x\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
|
||||
}
|
||||
|
||||
/** Reads a integer register. */
|
||||
IntReg
|
||||
InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
|
||||
threadNumber, seqNum, idx, instSrc[idx].intVal);
|
||||
return instSrc[idx].intVal;
|
||||
}
|
||||
|
||||
/** Reads a FP register. */
|
||||
FloatReg
|
||||
InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
|
||||
"as %x, %08f.\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
|
||||
return instSrc[idx].fpVal.f;
|
||||
}
|
||||
|
||||
|
||||
/** Reads a FP register as a integer. */
|
||||
FloatRegBits
|
||||
InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
|
||||
"as %x, %08f.\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
|
||||
return instSrc[idx].fpVal.i;
|
||||
}
|
||||
|
||||
/** 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::readMiscRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
|
||||
" read as %#x.\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].intVal);
|
||||
return instSrc[idx].intVal;
|
||||
}
|
||||
|
||||
|
||||
/** 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[idx].type = Integer;
|
||||
instResult[idx].res.intVal = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
|
||||
"being set to %#x.\n", threadNumber, seqNum, idx, val);
|
||||
}
|
||||
|
||||
MiscReg
|
||||
InOrderDynInst::readRegOtherThread(unsigned reg_idx, ThreadID 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].type = Integer;
|
||||
instResult[idx].res.intVal = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
|
||||
"being set to %#x (result-tick:%i).\n",
|
||||
threadNumber, seqNum, idx, val, instResult[idx].tick);
|
||||
}
|
||||
|
||||
/** Sets a FP register. */
|
||||
void
|
||||
InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
instResult[idx].type = Float;
|
||||
instResult[idx].res.fpVal.f = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. %i "
|
||||
"being set to %#x, %08f (result-tick:%i).\n",
|
||||
threadNumber, seqNum, idx, val, val, instResult[idx].tick);
|
||||
}
|
||||
|
||||
/** Sets a FP register as a integer. */
|
||||
void
|
||||
InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val)
|
||||
{
|
||||
instResult[idx].type = FloatBits;
|
||||
instResult[idx].res.fpVal.i = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
|
||||
"being set to %#x (result-tick:%i).\n",
|
||||
threadNumber, seqNum, idx, val, instResult[idx].tick);
|
||||
}
|
||||
|
||||
/** 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,
|
||||
ThreadID tid)
|
||||
{
|
||||
if (tid == InvalidThreadID) {
|
||||
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);
|
||||
}
|
||||
|
||||
Fault
|
||||
InOrderDynInst::readMem(Addr addr, uint8_t *data,
|
||||
unsigned size, unsigned flags)
|
||||
{
|
||||
return cpu->read(this, addr, data, size, flags);
|
||||
}
|
||||
|
||||
Fault
|
||||
InOrderDynInst::writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
return cpu->write(this, data, size, addr, flags, res);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderDynInst::dump()
|
||||
{
|
||||
cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
|
||||
cout << staticInst->disassemble(pc.instAddr());
|
||||
cprintf("'\n");
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::dump(std::string &outstring)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "T" << threadNumber << " : " << pc << " "
|
||||
<< staticInst->disassemble(pc.instAddr());
|
||||
|
||||
outstring = s.str();
|
||||
}
|
||||
1060
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.hh
Normal file
1060
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.hh
Normal file
File diff suppressed because it is too large
Load Diff
96
simulators/gem5/src/cpu/inorder/inorder_trace.cc
Normal file
96
simulators/gem5/src/cpu/inorder/inorder_trace.cc
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/inorder_trace.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/ExecEnable.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 (!Debug::ExecEnable)
|
||||
return NULL;
|
||||
|
||||
if (!Trace::enabled)
|
||||
return NULL;
|
||||
|
||||
return new InOrderTraceRecord(num_stages, stage_tracing, tc, 0);
|
||||
}
|
||||
|
||||
InOrderTraceRecord *
|
||||
InOrderTrace::getInstRecord(Tick when, ThreadContext *tc,
|
||||
const StaticInstPtr staticInst, TheISA::PCState _pc,
|
||||
const StaticInstPtr macroStaticInst)
|
||||
{
|
||||
return new InOrderTraceRecord(ThePipeline::NumStages, true, tc, _pc);
|
||||
}
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ExeTracer Simulation Object
|
||||
//
|
||||
Trace::InOrderTrace *
|
||||
InOrderTraceParams::create()
|
||||
{
|
||||
return new Trace::InOrderTrace(this);
|
||||
};
|
||||
|
||||
98
simulators/gem5/src/cpu/inorder/inorder_trace.hh
Normal file
98
simulators/gem5/src/cpu/inorder/inorder_trace.hh
Normal file
@ -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 __CPU_INORDER_INORDER_TRACE_HH__
|
||||
#define __CPU_INORDER_INORDER_TRACE_HH__
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "base/types.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "params/InOrderTrace.hh"
|
||||
#include "sim/insttracer.hh"
|
||||
|
||||
class ThreadContext;
|
||||
|
||||
namespace Trace {
|
||||
|
||||
class InOrderTraceRecord : public ExeTracerRecord
|
||||
{
|
||||
public:
|
||||
InOrderTraceRecord(unsigned num_stages, bool _stage_tracing,
|
||||
ThreadContext *_thread, TheISA::PCState _pc, bool spec = false)
|
||||
: ExeTracerRecord(0, _thread, NULL, _pc, 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(TheISA::PCState _pc) { pc = _pc; }
|
||||
};
|
||||
|
||||
class InOrderTrace : public InstTracer
|
||||
{
|
||||
public:
|
||||
InOrderTrace(const InOrderTraceParams *p) : InstTracer(p)
|
||||
{}
|
||||
|
||||
InOrderTraceRecord *
|
||||
getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc);
|
||||
|
||||
InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
|
||||
const StaticInstPtr staticInst, TheISA::PCState pc,
|
||||
const StaticInstPtr macroStaticInst = NULL);
|
||||
};
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#endif // __CPU_INORDER_INORDER_TRACE_HH__
|
||||
122
simulators/gem5/src/cpu/inorder/params.hh
Normal file
122
simulators/gem5/src/cpu/inorder/params.hh
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_PARAMS_HH__
|
||||
#define __CPU_INORDER_PARAMS_HH__
|
||||
|
||||
#include "cpu/base.hh"
|
||||
|
||||
//Forward declarations
|
||||
class FunctionalMemory;
|
||||
class Process;
|
||||
class MemObject;
|
||||
class MemInterface;
|
||||
|
||||
/**
|
||||
* This file defines the parameters that will be used for the InOrderCPU.
|
||||
* This must be defined externally so that the Impl can have a params class
|
||||
* defined that it can pass to all of the individual stages.
|
||||
*/
|
||||
|
||||
class InOrderParams : public BaseCPU::Params
|
||||
{
|
||||
public:
|
||||
|
||||
// Workloads
|
||||
std::vector<Process *> workload;
|
||||
Process *process;
|
||||
|
||||
//
|
||||
// Memory System/Caches
|
||||
//
|
||||
unsigned cachePorts;
|
||||
std::string fetchMemPort;
|
||||
std::string dataMemPort;
|
||||
|
||||
//
|
||||
// Branch predictor (BP & BTB)
|
||||
//
|
||||
std::string predType;
|
||||
unsigned localPredictorSize;
|
||||
unsigned localCtrBits;
|
||||
unsigned localHistoryTableSize;
|
||||
unsigned localHistoryBits;
|
||||
unsigned globalPredictorSize;
|
||||
unsigned globalCtrBits;
|
||||
unsigned globalHistoryBits;
|
||||
unsigned choicePredictorSize;
|
||||
unsigned choiceCtrBits;
|
||||
unsigned BTBEntries;
|
||||
unsigned BTBTagSize;
|
||||
unsigned RASSize;
|
||||
|
||||
// Pipeline Parameters
|
||||
unsigned stageWidth;
|
||||
|
||||
// InOrderCPU Simulation Parameters
|
||||
unsigned instShiftAmt;
|
||||
unsigned activity;
|
||||
unsigned deferRegistration;
|
||||
|
||||
//
|
||||
// Memory Parameters
|
||||
//
|
||||
unsigned memBlockSize;
|
||||
|
||||
//
|
||||
// Multiply Divide Unit
|
||||
//
|
||||
// @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr,
|
||||
// then MDU must be defined as its own SimObject so that an arbitrary # can
|
||||
// be defined with different parameters
|
||||
/** Latency & Repeat Rate for Multiply Insts */
|
||||
unsigned multLatency;
|
||||
unsigned multRepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 8-bit Divide Insts */
|
||||
unsigned div8Latency;
|
||||
unsigned div8RepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 16-bit Divide Insts */
|
||||
unsigned div16Latency;
|
||||
unsigned div16RepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 24-bit Divide Insts */
|
||||
unsigned div24Latency;
|
||||
unsigned div24RepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 32-bit Divide Insts */
|
||||
unsigned div32Latency;
|
||||
unsigned div32RepeatRate;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // _CPU_INORDER_PARAMS_HH__
|
||||
1125
simulators/gem5/src/cpu/inorder/pipeline_stage.cc
Normal file
1125
simulators/gem5/src/cpu/inorder/pipeline_stage.cc
Normal file
File diff suppressed because it is too large
Load Diff
349
simulators/gem5/src/cpu/inorder/pipeline_stage.hh
Normal file
349
simulators/gem5/src/cpu/inorder/pipeline_stage.hh
Normal file
@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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 "cpu/inorder/comm.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "params/InOrderCPU.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*/
|
||||
ThreadID numThreads;
|
||||
|
||||
/** Stage status. */
|
||||
StageStatus _status;
|
||||
|
||||
/** Per-thread status. */
|
||||
ThreadStatus stageStatus[ThePipeline::MaxThreads];
|
||||
|
||||
public:
|
||||
PipelineStage(Params *params, unsigned stage_num);
|
||||
|
||||
virtual ~PipelineStage();
|
||||
|
||||
/** PipelineStage initialization. */
|
||||
void init(Params *params);
|
||||
|
||||
/** Returns the name of stage. */
|
||||
std::string name() const;
|
||||
|
||||
/** Registers statistics. */
|
||||
void regStats();
|
||||
|
||||
/** Sets CPU pointer. */
|
||||
void setCPU(InOrderCPU *cpu_ptr);
|
||||
|
||||
/** 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<ThreadID> *at_ptr);
|
||||
|
||||
bool nextStageQueueValid(int stage_num);
|
||||
|
||||
bool isBlocked(ThreadID 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.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
/** Set a resource stall in the pipeline-stage */
|
||||
void setResStall(ResReqPtr res_req, ThreadID tid);
|
||||
|
||||
/** Unset a resource stall in the pipeline-stage */
|
||||
void unsetResStall(ResReqPtr res_req, ThreadID tid);
|
||||
|
||||
/** Remove all stall signals for a particular thread; */
|
||||
void removeStalls(ThreadID 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.
|
||||
*/
|
||||
void processThread(bool &status_change, ThreadID 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(ThreadID tid);
|
||||
|
||||
/** Process all resources on an instruction's resource schedule */
|
||||
bool processInstSchedule(DynInstPtr inst, int &reqs_processed);
|
||||
|
||||
/** Is there room in the next stage buffer for this instruction? */
|
||||
bool canSendInstToStage(unsigned stage_num);
|
||||
|
||||
/** Send an instruction to the next stage buffer */
|
||||
bool sendInstToNextStage(DynInstPtr inst);
|
||||
|
||||
/** 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. */
|
||||
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. */
|
||||
void readStallSignals(ThreadID tid);
|
||||
|
||||
/** Checks all input signals and updates stage's status appropriately. */
|
||||
bool checkSignalsAndUpdate(ThreadID tid);
|
||||
|
||||
/** Checks all stall signals, and returns if any are true. */
|
||||
bool checkStall(ThreadID 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.
|
||||
*/
|
||||
bool block(ThreadID tid);
|
||||
|
||||
void blockDueToBuffer(ThreadID 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.
|
||||
*/
|
||||
bool unblock(ThreadID tid);
|
||||
|
||||
|
||||
public:
|
||||
void activateThread(ThreadID tid);
|
||||
|
||||
/** Setup Squashing Information to be passed back thru the pipeline */
|
||||
void setupSquash(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
virtual void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Perform squash of instructions above seq_num */
|
||||
virtual void squash(InstSeqNum squash_num, ThreadID tid);
|
||||
|
||||
/** Squash instructions from stage buffer */
|
||||
void squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void dumpInsts();
|
||||
|
||||
protected:
|
||||
/** CPU interface. */
|
||||
InOrderCPU *cpu;
|
||||
|
||||
Trace::InOrderTrace *tracer;
|
||||
|
||||
/** List of active thread ids */
|
||||
std::list<ThreadID> *activeThreads;
|
||||
|
||||
/** Buffer of instructions switched out to mem-stall.
|
||||
* Only used when using SwitchOnCacheMiss threading model
|
||||
* Used as 1-to-1 mapping between ThreadID and Entry.
|
||||
*/
|
||||
std::vector<DynInstPtr> switchedOutBuffer;
|
||||
std::vector<bool> switchedOutValid;
|
||||
|
||||
/** Instructions that we've processed this tick
|
||||
* NOTE: "Processed" means completed at least 1 instruction request
|
||||
*/
|
||||
unsigned instsProcessed;
|
||||
|
||||
/** Skid buffer between previous stage and this one. */
|
||||
std::list<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];
|
||||
|
||||
/** 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];
|
||||
|
||||
/** Instruction used for squashing branch (used for MIPS) */
|
||||
DynInstPtr squashInst[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;
|
||||
|
||||
bool idle;
|
||||
|
||||
/** Source of possible stalls. */
|
||||
struct Stalls {
|
||||
bool stage[ThePipeline::NumStages];
|
||||
std::vector<ResReqPtr> resources;
|
||||
};
|
||||
|
||||
/** Tracks stage/resource stalls */
|
||||
Stalls stalls[ThePipeline::MaxThreads];
|
||||
|
||||
/** Number of cycles 0 instruction(s) are processed. */
|
||||
Stats::Scalar idleCycles;
|
||||
|
||||
/** Number of cycles 1+ instructions are processed. */
|
||||
Stats::Scalar runCycles;
|
||||
|
||||
/** Percentage of cycles 1+ instructions are processed. */
|
||||
Stats::Formula utilization;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
166
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.cc
Normal file
166
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.cc
Normal file
@ -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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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;
|
||||
}
|
||||
|
||||
};
|
||||
146
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.hh
Normal file
146
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.hh
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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
|
||||
242
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.cc
Normal file
242
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.cc
Normal file
@ -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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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;
|
||||
}
|
||||
|
||||
};
|
||||
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.hh
Normal file
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.hh
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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 <map>
|
||||
#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 = 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
|
||||
240
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
Normal file
240
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
Normal file
@ -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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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;
|
||||
}
|
||||
|
||||
};
|
||||
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
Normal file
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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 <map>
|
||||
#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 = 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
|
||||
85
simulators/gem5/src/cpu/inorder/pipeline_traits.hh
Normal file
85
simulators/gem5/src/cpu/inorder/pipeline_traits.hh
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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;
|
||||
class ScheduleEntry;
|
||||
class ResourceSked;
|
||||
|
||||
/* This Namespace contains constants, typedefs, functions and
|
||||
* objects specific to the Pipeline Implementation.
|
||||
*/
|
||||
namespace ThePipeline {
|
||||
// Pipeline Constants
|
||||
const unsigned NumStages = 5;
|
||||
const ThreadID MaxThreads = 1;
|
||||
const unsigned BackEndStartStage = 2;
|
||||
|
||||
// List of Resources The Pipeline Uses
|
||||
enum ResourceId {
|
||||
FetchSeq = 0,
|
||||
ICache,
|
||||
Decode,
|
||||
BPred,
|
||||
FetchBuff,
|
||||
RegManager,
|
||||
AGEN,
|
||||
ExecUnit,
|
||||
MDU,
|
||||
DCache,
|
||||
Grad,
|
||||
FetchBuff2
|
||||
};
|
||||
|
||||
typedef InOrderCPUParams Params;
|
||||
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
|
||||
|
||||
//////////////////////////
|
||||
// RESOURCE SCHEDULING
|
||||
//////////////////////////
|
||||
typedef ResourceSked ResSchedule;
|
||||
typedef ResourceSked* RSkedPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
306
simulators/gem5/src/cpu/inorder/reg_dep_map.cc
Normal file
306
simulators/gem5/src/cpu/inorder/reg_dep_map.cc
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "debug/RegDepMap.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
using namespace ThePipeline;
|
||||
|
||||
RegDepMap::RegDepMap(int size)
|
||||
{
|
||||
regMap.resize(InOrderCPU::NumRegTypes);
|
||||
regMap[InOrderCPU::IntType].resize(NumIntRegs);
|
||||
regMap[InOrderCPU::FloatType].resize(NumFloatRegs);
|
||||
regMap[InOrderCPU::MiscType].resize(NumMiscRegs);
|
||||
}
|
||||
|
||||
RegDepMap::~RegDepMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
string
|
||||
RegDepMap::name()
|
||||
{
|
||||
return cpu->name() + ".RegDepMap";
|
||||
}
|
||||
|
||||
std::string RegDepMap::mapNames[InOrderCPU::NumRegTypes] =
|
||||
{"IntReg", "FloatReg", "MiscReg"};
|
||||
|
||||
void
|
||||
RegDepMap::setCPU(InOrderCPU *_cpu)
|
||||
{
|
||||
cpu = _cpu;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::clear()
|
||||
{
|
||||
for (int i = 0; i < regMap.size(); i++) {
|
||||
for (int j = 0; j < regMap[j].size(); j++)
|
||||
regMap[i][j].clear();
|
||||
regMap[i].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->instName(),
|
||||
dest_regs);
|
||||
|
||||
for (int i = 0; i < dest_regs; i++) {
|
||||
InOrderCPU::RegType reg_type;
|
||||
TheISA::RegIndex raw_idx = inst->destRegIdx(i);
|
||||
TheISA::RegIndex flat_idx = cpu->flattenRegIdx(raw_idx,
|
||||
reg_type,
|
||||
inst->threadNumber);
|
||||
|
||||
DPRINTF(RegDepMap, "[sn:%i] #%i flattened %i to %i.\n",
|
||||
inst->seqNum, i, raw_idx, flat_idx);
|
||||
|
||||
inst->flattenDestReg(i, flat_idx);
|
||||
|
||||
if (flat_idx == TheISA::ZeroReg && reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(RegDepMap, "[sn:%i]: Ignoring Insert-Dependency tracking for "
|
||||
"ISA-ZeroReg (Int. Reg %i).\n", inst->seqNum,
|
||||
flat_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
insert(reg_type, flat_idx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RegDepMap::insert(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
DPRINTF(RegDepMap, "Inserting [sn:%i] onto %s dep. list for "
|
||||
"reg. idx %i.\n", inst->seqNum, mapNames[reg_type],
|
||||
idx);
|
||||
|
||||
regMap[reg_type][idx].push_back(inst);
|
||||
|
||||
inst->setRegDepEntry();
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::remove(DynInstPtr inst)
|
||||
{
|
||||
if (inst->isRegDepEntry()) {
|
||||
int dest_regs = inst->numDestRegs();
|
||||
|
||||
DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map. for "
|
||||
", %s (dest. regs = %i).\n",
|
||||
inst->seqNum,
|
||||
inst->instName(),
|
||||
dest_regs);
|
||||
|
||||
|
||||
for (int i = 0; i < dest_regs; i++) {
|
||||
RegIndex flat_idx = inst->flattenedDestRegIdx(i);
|
||||
InOrderCPU::RegType reg_type = cpu->getRegType(inst->destRegIdx(i));
|
||||
|
||||
// Merge Dyn Inst & CPU Result Types
|
||||
if (flat_idx == TheISA::ZeroReg &&
|
||||
reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(RegDepMap, "[sn:%i]: Ignoring Remove-Dependency tracking for "
|
||||
"ISA-ZeroReg (Int. Reg %i).\n", inst->seqNum,
|
||||
flat_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
remove(reg_type, flat_idx, inst);
|
||||
}
|
||||
|
||||
inst->clearRegDepEntry();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::remove(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][idx].begin();
|
||||
std::list<DynInstPtr>::iterator list_end = regMap[reg_type][idx].end();
|
||||
|
||||
|
||||
while (list_it != list_end) {
|
||||
if((*list_it) == inst) {
|
||||
DPRINTF(RegDepMap, "Removing [sn:%i] from %s dep. list for "
|
||||
"reg. idx %i.\n", inst->seqNum, mapNames[reg_type],
|
||||
idx);
|
||||
regMap[reg_type][idx].erase(list_it);
|
||||
return;
|
||||
}
|
||||
list_it++;
|
||||
}
|
||||
panic("[sn:%i] Did not find entry for %i, type:%i\n", inst->seqNum, idx, reg_type);
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::removeFront(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][idx].begin();
|
||||
|
||||
DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on reg. idx "
|
||||
"%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum);
|
||||
|
||||
assert(list_it != regMap[reg_type][idx].end());
|
||||
|
||||
assert(inst == (*list_it));
|
||||
|
||||
regMap[reg_type][idx].erase(list_it);
|
||||
}
|
||||
|
||||
bool
|
||||
RegDepMap::canRead(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
if (regMap[reg_type][idx].size() == 0)
|
||||
return true;
|
||||
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][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(uint8_t reg_type, unsigned reg_idx, DynInstPtr inst)
|
||||
{
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][reg_idx].begin();
|
||||
std::list<DynInstPtr>::iterator list_end = regMap[reg_type][reg_idx].end();
|
||||
|
||||
DynInstPtr forward_inst = NULL;
|
||||
|
||||
// Look for instruction immediately in front of requestor to supply
|
||||
// data
|
||||
while (list_it != list_end &&
|
||||
(*list_it)->seqNum < inst->seqNum) {
|
||||
forward_inst = (*list_it);
|
||||
list_it++;
|
||||
}
|
||||
|
||||
if (forward_inst) {
|
||||
int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx);
|
||||
assert(dest_reg_idx != -1);
|
||||
|
||||
DPRINTF(RegDepMap, "[sn:%i] Found potential forwarding value for reg %i "
|
||||
" w/ [sn:%i] dest. reg. #%i\n",
|
||||
inst->seqNum, reg_idx, forward_inst->seqNum, dest_reg_idx);
|
||||
|
||||
if (forward_inst->isExecuted() &&
|
||||
forward_inst->readResultTime(dest_reg_idx) < curTick()) {
|
||||
return forward_inst;
|
||||
} else {
|
||||
if (!forward_inst->isExecuted()) {
|
||||
DPRINTF(RegDepMap, "[sn:%i] Can't get value through "
|
||||
"forwarding, [sn:%i] %s has not been executed yet.\n",
|
||||
inst->seqNum, forward_inst->seqNum, forward_inst->instName());
|
||||
} else if (forward_inst->readResultTime(dest_reg_idx) >= curTick()) {
|
||||
DPRINTF(RegDepMap, "[sn:%i] Can't get value through "
|
||||
"forwarding, [sn:%i] executed on tick:%i.\n",
|
||||
inst->seqNum, forward_inst->seqNum,
|
||||
forward_inst->readResultTime(dest_reg_idx));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n",
|
||||
inst->seqNum);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegDepMap::canWrite(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
if (regMap[reg_type][idx].size() == 0)
|
||||
return true;
|
||||
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][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;
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::dump()
|
||||
{
|
||||
for (int reg_type = 0; reg_type < InOrderCPU::NumRegTypes; reg_type++) {
|
||||
for (int idx=0; idx < regMap.size(); idx++) {
|
||||
if (regMap[idx].size() > 0) {
|
||||
cprintf("Reg #%i (size:%i): ", idx, regMap[reg_type][idx].size());
|
||||
|
||||
std::list<DynInstPtr>::iterator list_it =
|
||||
regMap[reg_type][idx].begin();
|
||||
std::list<DynInstPtr>::iterator list_end =
|
||||
regMap[reg_type][idx].end();
|
||||
|
||||
while (list_it != list_end) {
|
||||
cprintf("[sn:%i] ", (*list_it)->seqNum);
|
||||
list_it++;
|
||||
}
|
||||
cprintf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
simulators/gem5/src/cpu/inorder/reg_dep_map.hh
Normal file
117
simulators/gem5/src/cpu/inorder/reg_dep_map.hh
Normal file
@ -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_REG_DEP_MAP_HH
|
||||
#define CPU_INORDER_REG_DEP_MAP_HH
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
|
||||
class RegDepMap
|
||||
{
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef TheISA::RegIndex RegIndex;
|
||||
typedef uint8_t RegType;
|
||||
|
||||
RegDepMap(int size = TheISA::TotalNumRegs);
|
||||
~RegDepMap();
|
||||
|
||||
static std::string mapNames[];
|
||||
|
||||
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);
|
||||
|
||||
/** Remove all of a instruction's destination registers into map*/
|
||||
void remove(DynInstPtr inst);
|
||||
|
||||
/** Remove Front instruction from a destination register */
|
||||
void removeFront(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Is the current instruction able to read from this
|
||||
* destination register?
|
||||
*/
|
||||
bool canRead(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Is the current instruction able to get a forwarded value from
|
||||
* another instruction for this destination register?
|
||||
*/
|
||||
DynInstPtr canForward(uint8_t reg_type, unsigned reg_idx,
|
||||
DynInstPtr inst);
|
||||
|
||||
/** find an instruction to forward/bypass a value from */
|
||||
DynInstPtr findBypassInst(RegIndex idx);
|
||||
|
||||
/** Is the current instruction able to write to this
|
||||
* destination register?
|
||||
*/
|
||||
bool canWrite(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Size of Dependency of Map */
|
||||
int depSize(RegIndex idx);
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
/** Insert an instruction into a specific destination register index
|
||||
* onto map.
|
||||
*/
|
||||
void insert(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Remove a specific instruction and dest. register index from map */
|
||||
void remove(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
typedef std::vector<std::list<DynInstPtr> > DepMap;
|
||||
std::vector<DepMap> regMap;
|
||||
|
||||
InOrderCPU *cpu;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
529
simulators/gem5/src/cpu/inorder/resource.cc
Normal file
529
simulators/gem5/src/cpu/inorder/resource.cc
Normal file
@ -0,0 +1,529 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "base/str.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/ExecFaulting.hh"
|
||||
#include "debug/RefCount.hh"
|
||||
#include "debug/ResReqCount.hh"
|
||||
#include "debug/Resource.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),
|
||||
resourceEvent(NULL)
|
||||
{
|
||||
reqs.resize(width);
|
||||
|
||||
// Use to deny a instruction a resource.
|
||||
deniedReq = new ResourceRequest(this);
|
||||
deniedReq->valid = true;
|
||||
}
|
||||
|
||||
Resource::~Resource()
|
||||
{
|
||||
if (resourceEvent) {
|
||||
delete [] resourceEvent;
|
||||
}
|
||||
|
||||
delete deniedReq;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
delete reqs[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Resource::init()
|
||||
{
|
||||
// If the resource has a zero-cycle (no latency)
|
||||
// function, then no reason to have events
|
||||
// that will process them for the right tick
|
||||
if (latency > 0)
|
||||
resourceEvent = new ResourceEvent[width];
|
||||
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
reqs[i] = new ResourceRequest(this);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (resourceEvent) {
|
||||
resourceEvent[slot_idx].init(this, slot_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Resource::name()
|
||||
{
|
||||
return cpu->name() + "." + resName;
|
||||
}
|
||||
|
||||
int
|
||||
Resource::slotsAvail()
|
||||
{
|
||||
return availSlots.size();
|
||||
}
|
||||
|
||||
int
|
||||
Resource::slotsInUse()
|
||||
{
|
||||
return width - availSlots.size();
|
||||
}
|
||||
|
||||
void
|
||||
Resource::freeSlot(int slot_idx)
|
||||
{
|
||||
DPRINTF(Resource, "Deallocating [slot:%i].\n",
|
||||
slot_idx);
|
||||
|
||||
// Put slot number on this resource's free list
|
||||
availSlots.push_back(slot_idx);
|
||||
|
||||
// Invalidate Request & Reset it's flags
|
||||
reqs[slot_idx]->clearRequest();
|
||||
}
|
||||
|
||||
int
|
||||
Resource::findSlot(DynInstPtr inst)
|
||||
{
|
||||
int slot_num = -1;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (reqs[i]->valid &&
|
||||
reqs[i]->getInst()->seqNum == inst->seqNum) {
|
||||
slot_num = reqs[i]->getSlot();
|
||||
}
|
||||
}
|
||||
return slot_num;
|
||||
}
|
||||
|
||||
int
|
||||
Resource::getSlot(DynInstPtr inst)
|
||||
{
|
||||
int slot_num = -1;
|
||||
|
||||
if (slotsAvail() != 0) {
|
||||
slot_num = availSlots[0];
|
||||
|
||||
vector<int>::iterator vect_it = availSlots.begin();
|
||||
|
||||
assert(slot_num == *vect_it);
|
||||
|
||||
availSlots.erase(vect_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 = -1;
|
||||
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) {
|
||||
DPRINTF(Resource, "Allocating [slot:%i] for [tid:%i]: [sn:%i]\n",
|
||||
slot_num, inst->readTid(), inst->seqNum);
|
||||
|
||||
// Get Stage # from Schedule Entry
|
||||
stage_num = inst->curSkedEntry->stageNum;
|
||||
unsigned cmd = inst->curSkedEntry->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());
|
||||
}
|
||||
|
||||
try_request = true;
|
||||
} else {
|
||||
DPRINTF(Resource, "No slot available for [tid:%i]: [sn:%i]\n",
|
||||
inst->readTid(), inst->seqNum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
reqs[slot_num]->setRequest(inst, stage_num, id, slot_num, cmd);
|
||||
return reqs[slot_num];
|
||||
}
|
||||
|
||||
ResReqPtr
|
||||
Resource::findRequest(DynInstPtr inst)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (reqs[i]->valid &&
|
||||
reqs[i]->getInst() == inst) {
|
||||
return reqs[i];
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//@todo: have each resource print out command their executing
|
||||
DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n",
|
||||
reqs[slot_idx]->getTid(), name());
|
||||
reqs[slot_idx]->setCompleted(true);
|
||||
reqs[slot_idx]->done();
|
||||
}
|
||||
|
||||
void
|
||||
Resource::deactivateThread(ThreadID tid)
|
||||
{
|
||||
// In the most basic case, deactivation means squashing everything
|
||||
// from a particular thread
|
||||
DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid, tid);
|
||||
squash(dummy_inst, 0, 0, tid);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
|
||||
{
|
||||
// Squash In Pipeline Stage
|
||||
cpu->pipelineStage[stage_num]->setupSquash(inst, tid);
|
||||
|
||||
// Schedule Squash Through-out Resource Pool
|
||||
cpu->resPool->scheduleEvent(
|
||||
(InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
{
|
||||
//@todo: check squash seq num before squashing. can save time going
|
||||
// through this function.
|
||||
for (int i = 0; i < width; i++) {
|
||||
ResReqPtr req_ptr = reqs[i];
|
||||
DynInstPtr inst = req_ptr->getInst();
|
||||
|
||||
if (req_ptr->valid &&
|
||||
inst->readTid() == tid &&
|
||||
inst->seqNum > squash_seq_num) {
|
||||
|
||||
DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
|
||||
req_ptr->getInst()->readTid(),
|
||||
req_ptr->getInst()->seqNum);
|
||||
|
||||
req_ptr->setSquashed();
|
||||
|
||||
int req_slot_num = req_ptr->getSlot();
|
||||
|
||||
if (latency > 0) {
|
||||
if (resourceEvent[req_slot_num].scheduled())
|
||||
unscheduleEvent(req_slot_num);
|
||||
}
|
||||
|
||||
freeSlot(req_slot_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Resource::squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
{
|
||||
squash(inst, stage_num, squash_seq_num, tid);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::squashThenTrap(int stage_num, DynInstPtr inst)
|
||||
{
|
||||
ThreadID tid = inst->readTid();
|
||||
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
if (inst->traceData) {
|
||||
if (inst->staticInst &&
|
||||
inst->fault != NoFault && DTRACE(ExecFaulting)) {
|
||||
inst->traceData->setStageCycle(stage_num, curTick());
|
||||
inst->traceData->setFetchSeq(inst->seqNum);
|
||||
inst->traceData->dump();
|
||||
}
|
||||
|
||||
delete inst->traceData;
|
||||
inst->traceData = NULL;
|
||||
}
|
||||
|
||||
cpu->trapContext(inst->fault, tid, inst);
|
||||
}
|
||||
|
||||
Tick
|
||||
Resource::ticks(int num_cycles)
|
||||
{
|
||||
return cpu->ticks(num_cycles);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Resource::scheduleExecution(int slot_num)
|
||||
{
|
||||
if (latency >= 1) {
|
||||
scheduleEvent(slot_num, 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",
|
||||
reqs[slot_idx]->inst->readTid(),
|
||||
reqs[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::maxReqCount = 0;
|
||||
|
||||
ResourceRequest::ResourceRequest(Resource *_res)
|
||||
: res(_res), inst(NULL), stagePasses(0), valid(false), doneInResource(false),
|
||||
completed(false), squashed(false), processing(false),
|
||||
memStall(false)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceRequest::~ResourceRequest()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
res->cpu->resReqCount--;
|
||||
DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID,
|
||||
res->cpu->resReqCount);
|
||||
#endif
|
||||
inst = NULL;
|
||||
}
|
||||
|
||||
std::string
|
||||
ResourceRequest::name()
|
||||
{
|
||||
return csprintf("%s[slot:%i]:", res->name(), slotNum);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::setRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num, unsigned _cmd)
|
||||
{
|
||||
valid = true;
|
||||
inst = _inst;
|
||||
stageNum = stage_num;
|
||||
resIdx = res_idx;
|
||||
slotNum = slot_num;
|
||||
cmd = _cmd;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::clearRequest()
|
||||
{
|
||||
valid = false;
|
||||
inst = NULL;
|
||||
stagePasses = 0;
|
||||
completed = false;
|
||||
doneInResource = false;
|
||||
squashed = false;
|
||||
memStall = false;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::freeSlot()
|
||||
{
|
||||
assert(res);
|
||||
|
||||
// Free Slot So Another Instruction Can Use This Resource
|
||||
res->freeSlot(slotNum);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::done(bool completed)
|
||||
{
|
||||
DPRINTF(Resource, "done with request from "
|
||||
"[sn:%i] [tid:%i].\n",
|
||||
inst->seqNum, inst->readTid());
|
||||
|
||||
setCompleted(completed);
|
||||
|
||||
doneInResource = true;
|
||||
}
|
||||
|
||||
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() const
|
||||
{
|
||||
string desc = resource->name() + "-event:slot[" + to_string(slotIdx)
|
||||
+ "]";
|
||||
|
||||
return desc.c_str();
|
||||
}
|
||||
|
||||
void
|
||||
ResourceEvent::scheduleEvent(int delay)
|
||||
{
|
||||
assert(!scheduled() || squashed());
|
||||
resource->cpu->reschedule(this,
|
||||
curTick() + resource->ticks(delay), true);
|
||||
}
|
||||
414
simulators/gem5/src/cpu/inorder/resource.hh
Normal file
414
simulators/gem5/src/cpu/inorder/resource.hh
Normal file
@ -0,0 +1,414 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/types.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inst_seq.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 CacheRequest;
|
||||
typedef CacheRequest* CacheReqPtr;
|
||||
|
||||
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();
|
||||
|
||||
/** 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(ThreadID tid) { }
|
||||
|
||||
/** Deactivate Thread. Default action is to squash all instructions
|
||||
* from deactivated thread.
|
||||
*/
|
||||
virtual void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Resources that care about thread activation override this. */
|
||||
virtual void suspendThread(ThreadID tid) { }
|
||||
|
||||
/** Will be called the cycle before a context switch. Any bookkeeping
|
||||
* that needs to be kept for that, can be done here
|
||||
*/
|
||||
virtual void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) { }
|
||||
|
||||
/** Resources that care when an instruction has been graduated
|
||||
* can override this
|
||||
*/
|
||||
virtual void instGraduated(InstSeqNum seq_num, ThreadID tid) { }
|
||||
|
||||
/** Post-processsing for Trap Generated from this instruction */
|
||||
virtual void trap(Fault fault, ThreadID tid, DynInstPtr inst) { }
|
||||
|
||||
/** 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*/
|
||||
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 void doCacheAccess(DynInstPtr inst, uint64_t *write_result = NULL,
|
||||
CacheReqPtr split_req = NULL)
|
||||
{ panic("doCacheAccess undefined for %s", name()); }
|
||||
|
||||
/** Setup Squash to be sent out to pipeline and resource pool */
|
||||
void setupSquash(DynInstPtr inst, int stage_num, ThreadID tid);
|
||||
|
||||
/** Squash All Requests After This Seq Num */
|
||||
virtual void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Squash Requests Due to a Memory Stall (By Default, same as "squash" */
|
||||
virtual void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Handle Squash & Trap that occured from an instruction in a resource */
|
||||
void squashThenTrap(int stage_num, DynInstPtr inst);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** */
|
||||
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:
|
||||
/** List of all Requests the Resource is Servicing. Each request
|
||||
represents part of the resource's bandwidth
|
||||
*/
|
||||
std::vector<ResReqPtr> reqs;
|
||||
|
||||
/** 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;
|
||||
};
|
||||
|
||||
class ResourceEvent : public Event
|
||||
{
|
||||
public:
|
||||
/** Pointer to the Resource this is an event for */
|
||||
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() const;
|
||||
|
||||
/** Set slot idx for event */
|
||||
void setSlot(int slot) { slotIdx = slot; }
|
||||
|
||||
/** Schedule resource event, regardless of its current state. */
|
||||
void scheduleEvent(int 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 maxReqCount;
|
||||
|
||||
friend class Resource;
|
||||
|
||||
public:
|
||||
ResourceRequest(Resource *_res);
|
||||
|
||||
virtual ~ResourceRequest();
|
||||
|
||||
std::string name();
|
||||
|
||||
int reqID;
|
||||
|
||||
void setRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num, unsigned _cmd);
|
||||
|
||||
virtual void clearRequest();
|
||||
|
||||
/** Acknowledge that this is a request is done and remove
|
||||
* from resource.
|
||||
*/
|
||||
void done(bool completed = true);
|
||||
|
||||
void freeSlot();
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
// GET RESOURCE REQUEST IDENTIFICATION / INFO
|
||||
//
|
||||
/////////////////////////////////////////////
|
||||
/** Get Resource Index */
|
||||
int getResIdx() { return resIdx; }
|
||||
|
||||
/** Get Slot Number */
|
||||
int getSlot() { return slotNum; }
|
||||
bool hasSlot() { return slotNum >= 0; }
|
||||
|
||||
/** Get Stage Number */
|
||||
int getStageNum() { return stageNum; }
|
||||
|
||||
/** Set/Get Thread Ids */
|
||||
void setTid(ThreadID _tid) { tid = _tid; }
|
||||
ThreadID 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;
|
||||
|
||||
/** Not guaranteed to be set, used for debugging */
|
||||
InstSeqNum seqNum;
|
||||
|
||||
/** Command For This Resource */
|
||||
unsigned cmd;
|
||||
|
||||
short stagePasses;
|
||||
|
||||
bool valid;
|
||||
|
||||
bool doneInResource;
|
||||
|
||||
////////////////////////////////////////
|
||||
//
|
||||
// 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(bool cond = true) { processing = cond; }
|
||||
|
||||
/** Get/Set IsWaiting variables */
|
||||
bool isMemStall() { return memStall; }
|
||||
void setMemStall(bool stall = true) { memStall = stall; }
|
||||
|
||||
protected:
|
||||
/** Resource Identification */
|
||||
ThreadID tid;
|
||||
int stageNum;
|
||||
int resIdx;
|
||||
int slotNum;
|
||||
|
||||
/** Resource Request Status */
|
||||
bool completed;
|
||||
bool squashed;
|
||||
bool processing;
|
||||
|
||||
bool memStall;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_RESOURCE_HH__
|
||||
361
simulators/gem5/src/cpu/inorder/resource_pool.9stage.cc
Normal file
361
simulators/gem5/src/cpu/inorder/resource_pool.9stage.cc
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/resource_list.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
|
||||
: cpu(_cpu), instUnit(NULL), dataUnit(NULL)
|
||||
{
|
||||
//@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("itlb", ITLB, StageWidth, 0, _cpu, params));
|
||||
|
||||
|
||||
// Keep track of the instruction fetch unit so we can easily
|
||||
// provide a pointer to it in the CPU.
|
||||
instUnit = new FetchUnit("icache_port", ICache,
|
||||
StageWidth * MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(instUnit);
|
||||
|
||||
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("dtlb", DTLB, StageWidth, 0, _cpu, params));
|
||||
|
||||
// Keep track of the data load/store unit so we can easily provide
|
||||
// a pointer to it in the CPU.
|
||||
dataUnit = new CacheUnit("dcache_port", DCache,
|
||||
StageWidth * MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(dataUnit);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
ThreadID 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, ThreadID 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->squashSeqNum,
|
||||
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->squashSeqNum,
|
||||
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->squashSeqNum,
|
||||
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, ThreadID 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(ThreadID 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(ThreadID 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, ThreadID 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();
|
||||
}
|
||||
472
simulators/gem5/src/cpu/inorder/resource_pool.cc
Normal file
472
simulators/gem5/src/cpu/inorder/resource_pool.cc
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/resource_list.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/Resource.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
|
||||
: cpu(_cpu), instUnit(NULL), dataUnit(NULL)
|
||||
{
|
||||
//@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);
|
||||
|
||||
int stage_width = cpu->stageWidth;
|
||||
|
||||
// Declare Resource Objects
|
||||
// name - id - bandwidth - latency - CPU - Parameters
|
||||
// --------------------------------------------------
|
||||
resources.push_back(new FetchSeqUnit("fetch_seq_unit", FetchSeq,
|
||||
stage_width * 2, 0, _cpu, params));
|
||||
|
||||
// Keep track of the instruction fetch unit so we can easily
|
||||
// provide a pointer to it in the CPU.
|
||||
instUnit = new FetchUnit("icache_port", ICache,
|
||||
stage_width * 2 + MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(instUnit);
|
||||
|
||||
resources.push_back(new DecodeUnit("decode_unit", Decode,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new BranchPredictor("branch_predictor", BPred,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new InstBuffer("fetch_buffer_t0", FetchBuff, 4,
|
||||
0, _cpu, params));
|
||||
|
||||
resources.push_back(new UseDefUnit("regfile_manager", RegManager,
|
||||
stage_width * 3, 0, _cpu,
|
||||
params));
|
||||
|
||||
resources.push_back(new AGENUnit("agen_unit", AGEN,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new ExecutionUnit("execution_unit", ExecUnit,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new MultDivUnit("mult_div_unit", MDU,
|
||||
stage_width * 2,
|
||||
0,
|
||||
_cpu,
|
||||
params));
|
||||
|
||||
// Keep track of the data load/store unit so we can easily provide
|
||||
// a pointer to it in the CPU.
|
||||
dataUnit = new CacheUnit("dcache_port", DCache,
|
||||
stage_width * 2 + MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(dataUnit);
|
||||
|
||||
gradObjects.push_back(BPred);
|
||||
resources.push_back(new GraduationUnit("graduation_unit", Grad,
|
||||
stage_width, 0, _cpu,
|
||||
params));
|
||||
|
||||
resources.push_back(new InstBuffer("fetch_buffer_t1", FetchBuff2, 4,
|
||||
0, _cpu, params));
|
||||
|
||||
}
|
||||
|
||||
ResourcePool::~ResourcePool()
|
||||
{
|
||||
cout << "Deleting resources ..." << endl;
|
||||
|
||||
for (int i=0; i < resources.size(); i++) {
|
||||
DPRINTF(Resource, "Deleting resource: %s.\n", resources[i]->name());
|
||||
|
||||
delete resources[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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::print()
|
||||
{
|
||||
for (int i=0; i < resources.size(); i++) {
|
||||
DPRINTF(InOrderDynInst, "Res:%i %s\n",
|
||||
i, resources[i]->name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
ResourcePool::getResIdx(const ThePipeline::ResourceId &res_id)
|
||||
{
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
if (resources[idx]->getId() == res_id)
|
||||
return idx;
|
||||
}
|
||||
|
||||
// todo: change return value to int and return a -1 here
|
||||
// maybe even have enumerated type
|
||||
// panic for now...
|
||||
panic("Can't find resource idx for: %i\n", res_id);
|
||||
|
||||
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,
|
||||
ThreadID tid)
|
||||
{
|
||||
resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num,
|
||||
tid);
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Trap to all "
|
||||
"resources.\n", tid);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++)
|
||||
resources[idx]->trap(fault, tid, inst);
|
||||
}
|
||||
|
||||
int
|
||||
ResourcePool::slotsAvail(int res_idx)
|
||||
{
|
||||
return resources[res_idx]->slotsAvail();
|
||||
}
|
||||
|
||||
int
|
||||
ResourcePool::slotsInUse(int res_idx)
|
||||
{
|
||||
return resources[res_idx]->slotsInUse();
|
||||
}
|
||||
|
||||
//@todo: split this function and call this version schedulePoolEvent
|
||||
// and use this scheduleEvent for scheduling a specific event on
|
||||
// a resource
|
||||
//@todo: For arguments that arent being used in a ResPoolEvent, a dummyParam
|
||||
// or some typedef can be used to signify what's important info
|
||||
// to the event construction
|
||||
void
|
||||
ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
||||
int delay, int res_idx, ThreadID tid)
|
||||
{
|
||||
assert(delay >= 0);
|
||||
|
||||
Tick when = cpu->nextCycle(curTick() + cpu->ticks(delay));
|
||||
|
||||
switch ((int)e_type)
|
||||
{
|
||||
case ResourcePool::InstGraduated:
|
||||
{
|
||||
DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
|
||||
"Event for tick %i.\n", curTick() + delay);
|
||||
ResPoolEventPri grad_pri = ResGrad_Pri;
|
||||
ResPoolEvent *res_pool_event =
|
||||
new ResPoolEvent(this,
|
||||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->seqNum,
|
||||
inst->readTid(),
|
||||
grad_pri);
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
break;
|
||||
|
||||
case ResourcePool::SquashAll:
|
||||
{
|
||||
DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
|
||||
"tick %i.\n", curTick() + delay);
|
||||
ResPoolEventPri squash_pri = ResSquash_Pri;
|
||||
ResPoolEvent *res_pool_event =
|
||||
new ResPoolEvent(this,
|
||||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->squashSeqNum,
|
||||
inst->readTid(),
|
||||
squash_pri);
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
break;
|
||||
|
||||
case ResourcePool::UpdateAfterContextSwitch:
|
||||
{
|
||||
DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event "
|
||||
"for tick %i.\n",
|
||||
curTick() + delay);
|
||||
ResPoolEvent *res_pool_event = new ResPoolEvent(this,
|
||||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->seqNum,
|
||||
inst->readTid());
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
|
||||
InOrderCPU::eventNames[e_type]);
|
||||
}
|
||||
}
|
||||
|
||||
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, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
|
||||
" starting w/stage %i for all instructions above [sn:%i].\n",
|
||||
tid, stage_num, 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::squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum done_seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
|
||||
" starting w/stage %i for all instructions above [sn:%i].\n",
|
||||
tid, stage_num, done_seq_num);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
|
||||
tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::activateThread(ThreadID tid)
|
||||
{
|
||||
bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
|
||||
cpu->numActiveThreads() < 1 ||
|
||||
cpu->activeThreadId() == tid;
|
||||
|
||||
|
||||
if (do_activate) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
|
||||
"resources.\n", tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::deactivateThread(ThreadID 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::suspendThread(ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all "
|
||||
"resources.\n", tid);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[idx]->suspendThread(tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to "
|
||||
"appropriate resources.\n", tid, seq_num);
|
||||
|
||||
int num_resources = gradObjects.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[gradObjects[idx]]->instGraduated(seq_num, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n",
|
||||
tid);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[idx]->updateAfterContextSwitch(inst, tid);
|
||||
}
|
||||
}
|
||||
|
||||
ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
|
||||
InOrderCPU::CPUEventType e_type,
|
||||
DynInstPtr _inst,
|
||||
int stage_num,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID _tid,
|
||||
ResPoolEventPri res_pri)
|
||||
: Event(res_pri), resPool(_resPool),
|
||||
eventType(e_type), inst(_inst), seqNum(seq_num),
|
||||
stageNum(stage_num), tid(_tid)
|
||||
{ }
|
||||
|
||||
|
||||
void
|
||||
ResourcePool::ResPoolEvent::process()
|
||||
{
|
||||
switch ((int)eventType)
|
||||
{
|
||||
|
||||
case ResourcePool::InstGraduated:
|
||||
resPool->instGraduated(seqNum, tid);
|
||||
break;
|
||||
|
||||
case ResourcePool::SquashAll:
|
||||
resPool->squashAll(inst, stageNum, seqNum, tid);
|
||||
break;
|
||||
|
||||
case ResourcePool::UpdateAfterContextSwitch:
|
||||
resPool->updateAfterContextSwitch(inst, tid);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized Event Type");
|
||||
}
|
||||
|
||||
resPool->cpu->cpuEventRemoveList.push(this);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ResourcePool::ResPoolEvent::description() const
|
||||
{
|
||||
return "Resource Pool event";
|
||||
}
|
||||
|
||||
/** Schedule resource event, regardless of its current state. */
|
||||
void
|
||||
ResourcePool::ResPoolEvent::scheduleEvent(int delay)
|
||||
{
|
||||
InOrderCPU *cpu = resPool->cpu;
|
||||
assert(!scheduled() || squashed());
|
||||
cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
|
||||
}
|
||||
|
||||
/** Unschedule resource event, regardless of its current state. */
|
||||
void
|
||||
ResourcePool::ResPoolEvent::unscheduleEvent()
|
||||
{
|
||||
if (scheduled())
|
||||
squash();
|
||||
}
|
||||
250
simulators/gem5/src/cpu/inorder/resource_pool.hh
Normal file
250
simulators/gem5/src/cpu/inorder/resource_pool.hh
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/params.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class CacheUnit;
|
||||
class Event;
|
||||
class FetchUnit;
|
||||
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,
|
||||
UpdateAfterContextSwitch,
|
||||
Default
|
||||
};
|
||||
|
||||
enum ResPoolEventPri {
|
||||
ResPool_Pri = InOrderCPU::InOrderCPU_Pri - 5,
|
||||
ResGrad_Pri,
|
||||
ResSquash_Pri
|
||||
};
|
||||
|
||||
class ResPoolEvent : public Event
|
||||
{
|
||||
protected:
|
||||
/** Resource Pool */
|
||||
ResourcePool *resPool;
|
||||
|
||||
public:
|
||||
InOrderCPU::CPUEventType eventType;
|
||||
|
||||
DynInstPtr inst;
|
||||
|
||||
InstSeqNum seqNum;
|
||||
|
||||
int stageNum;
|
||||
|
||||
ThreadID tid;
|
||||
|
||||
public:
|
||||
/** Constructs a resource event. */
|
||||
ResPoolEvent(ResourcePool *_resPool,
|
||||
InOrderCPU::CPUEventType e_type,
|
||||
DynInstPtr _inst,
|
||||
int stage_num,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID _tid,
|
||||
ResPoolEventPri res_pri = ResPool_Pri);
|
||||
|
||||
/** Set Type of Event To Be Scheduled */
|
||||
void setEvent(InOrderCPU::CPUEventType e_type,
|
||||
DynInstPtr _inst,
|
||||
int stage_num,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID _tid)
|
||||
{
|
||||
eventType = e_type;
|
||||
inst = _inst;
|
||||
seqNum = seq_num;
|
||||
stageNum = stage_num;
|
||||
tid = _tid;
|
||||
}
|
||||
|
||||
/** Processes a resource event. */
|
||||
void process();
|
||||
|
||||
/** Returns the description of the resource event. */
|
||||
const char *description() const;
|
||||
|
||||
/** 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();
|
||||
|
||||
void print();
|
||||
|
||||
/** Register Statistics in All Resources */
|
||||
void regStats();
|
||||
|
||||
/** Returns a specific resource. */
|
||||
unsigned getResIdx(const ThePipeline::ResourceId &res_id);
|
||||
|
||||
/** Returns a pointer to a resource */
|
||||
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,
|
||||
ThreadID tid);
|
||||
|
||||
/** Squash All Resources in Pool after Done Seq. Num */
|
||||
void squashAll(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum done_seq_num, ThreadID tid);
|
||||
|
||||
/** Squash Resources in Pool after a memory stall
|
||||
* NOTE: Only use during Switch-On-Miss Thread model
|
||||
*/
|
||||
void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum done_seq_num, ThreadID tid);
|
||||
|
||||
/** Activate Thread in all resources */
|
||||
void activateThread(ThreadID tid);
|
||||
|
||||
/** De-Activate Thread in all resources */
|
||||
void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Suspend Thread in all resources */
|
||||
void suspendThread(ThreadID tid);
|
||||
|
||||
/** Broadcast Context Switch Update to all resources */
|
||||
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
/** Broadcast graduation to all resources */
|
||||
void instGraduated(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Broadcast trap to all resources */
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
/** 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, ThreadID 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];
|
||||
|
||||
/**
|
||||
* Get a pointer to the (always present) instruction fetch unit.
|
||||
*
|
||||
* @return the instruction unit
|
||||
*/
|
||||
FetchUnit *getInstUnit() const { return instUnit; }
|
||||
|
||||
/**
|
||||
* Get a pointer to the (always present) data load/store unit.
|
||||
*
|
||||
* @return the data cache unit
|
||||
*/
|
||||
CacheUnit *getDataUnit() const { return dataUnit; }
|
||||
|
||||
private:
|
||||
|
||||
/** The instruction fetch unit. */
|
||||
FetchUnit *instUnit;
|
||||
|
||||
/** The data load/store unit. */
|
||||
CacheUnit *dataUnit;
|
||||
|
||||
std::vector<Resource *> resources;
|
||||
|
||||
/** Resources that need to be updated on an inst. graduation */
|
||||
std::vector<int> gradObjects;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_RESOURCE_HH__
|
||||
233
simulators/gem5/src/cpu/inorder/resource_sked.cc
Normal file
233
simulators/gem5/src/cpu/inorder/resource_sked.cc
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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 <cstdio>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource_sked.hh"
|
||||
#include "debug/SkedCache.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
ResourceSked::ResourceSked()
|
||||
{
|
||||
stages.resize(NumStages);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::init()
|
||||
{
|
||||
assert(!stages[0].empty());
|
||||
|
||||
curSkedEntry = stages[0].begin();
|
||||
}
|
||||
|
||||
int
|
||||
ResourceSked::size()
|
||||
{
|
||||
int total = 0;
|
||||
for (int i = 0; i < stages.size(); i++) {
|
||||
total += stages[i].size();
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceSked::empty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::begin()
|
||||
{
|
||||
int num_stages = stages.size();
|
||||
for (int i = 0; i < num_stages; i++) {
|
||||
if (stages[i].size() > 0)
|
||||
return stages[i].begin();
|
||||
}
|
||||
|
||||
return stages[num_stages - 1].end();
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::end()
|
||||
{
|
||||
int num_stages = stages.size();
|
||||
return stages[num_stages - 1].end();
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::end(int stage_num)
|
||||
{
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::find(int stage_num, int cmd)
|
||||
{
|
||||
SkedIt stage_it = stages[stage_num].begin();
|
||||
SkedIt stage_end = stages[stage_num].end();
|
||||
|
||||
while (stage_it != stage_end) {
|
||||
if ((*stage_it)->cmd == cmd)
|
||||
return stage_it;
|
||||
stage_it++;
|
||||
}
|
||||
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
ScheduleEntry*
|
||||
ResourceSked::top()
|
||||
{
|
||||
assert(size() > 0);
|
||||
|
||||
return *curSkedEntry;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::pop()
|
||||
{
|
||||
int stage_num = (*curSkedEntry)->stageNum;
|
||||
|
||||
stages[stage_num].erase(curSkedEntry);
|
||||
|
||||
if (!stages[stage_num].empty()) {
|
||||
curSkedEntry = stages[stage_num].begin();
|
||||
} else {
|
||||
int next_stage = stage_num + 1;
|
||||
|
||||
while (next_stage < NumStages) {
|
||||
if (stages[next_stage].empty()) {
|
||||
next_stage++;
|
||||
} else {
|
||||
curSkedEntry = stages[next_stage].begin();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::push(ScheduleEntry* sked_entry)
|
||||
{
|
||||
int stage_num = sked_entry->stageNum;
|
||||
assert(stage_num < NumStages);
|
||||
|
||||
SkedIt pri_iter = findIterByPriority(sked_entry, stage_num);
|
||||
|
||||
stages[stage_num].insert(pri_iter, sked_entry);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::pushBefore(ScheduleEntry* sked_entry, int sked_cmd,
|
||||
int sked_cmd_idx)
|
||||
{
|
||||
|
||||
int stage_num = sked_entry->stageNum;
|
||||
assert(stage_num < NumStages);
|
||||
|
||||
SkedIt pri_iter = findIterByCommand(sked_entry, stage_num,
|
||||
sked_cmd, sked_cmd_idx);
|
||||
|
||||
assert(pri_iter != stages[stage_num].end() &&
|
||||
"Could not find command to insert in front of.");
|
||||
|
||||
stages[stage_num].insert(pri_iter, sked_entry);
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::findIterByPriority(ScheduleEntry* sked_entry, int stage_num)
|
||||
{
|
||||
if (stages[stage_num].empty()) {
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
int priority = sked_entry->priority;
|
||||
|
||||
SkedIt sked_it = stages[stage_num].begin();
|
||||
SkedIt sked_end = stages[stage_num].end();
|
||||
|
||||
while (sked_it != sked_end) {
|
||||
if ((*sked_it)->priority > priority)
|
||||
break;
|
||||
|
||||
sked_it++;
|
||||
}
|
||||
|
||||
return sked_it;
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num,
|
||||
int sked_cmd, int sked_cmd_idx)
|
||||
{
|
||||
if (stages[stage_num].empty()) {
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
SkedIt sked_it = stages[stage_num].begin();
|
||||
SkedIt sked_end = stages[stage_num].end();
|
||||
|
||||
while (sked_it != sked_end) {
|
||||
if ((*sked_it)->cmd == sked_cmd &&
|
||||
(sked_cmd_idx != -1) ? (*sked_it)->idx == sked_cmd_idx : true)
|
||||
break;
|
||||
|
||||
sked_it++;
|
||||
}
|
||||
|
||||
return sked_it;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::print()
|
||||
{
|
||||
for (int i = 0; i < stages.size(); i++) {
|
||||
//ccprintf(cerr, "Stage %i\n====\n", i);
|
||||
SkedIt sked_it = stages[i].begin();
|
||||
SkedIt sked_end = stages[i].end();
|
||||
while (sked_it != sked_end) {
|
||||
DPRINTF(SkedCache, "\t stage:%i res:%i cmd:%i idx:%i\n",
|
||||
(*sked_it)->stageNum,
|
||||
(*sked_it)->resNum,
|
||||
(*sked_it)->cmd,
|
||||
(*sked_it)->idx);
|
||||
sked_it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
285
simulators/gem5/src/cpu/inorder/resource_sked.hh
Normal file
285
simulators/gem5/src/cpu/inorder/resource_sked.hh
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_RESOURCE_SKED_HH__
|
||||
#define __CPU_INORDER_RESOURCE_SKED_HH__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
/** ScheduleEntry class represents a single function that an instruction
|
||||
wants to do at any pipeline stage. For example, if an instruction
|
||||
needs to be decoded and do a branch prediction all in one stage
|
||||
then each of those tasks would need it's own ScheduleEntry.
|
||||
|
||||
Each schedule entry corresponds to some resource that the instruction
|
||||
wants to interact with.
|
||||
|
||||
The file pipeline_traits.cc shows how a typical instruction schedule is
|
||||
made up of these schedule entries.
|
||||
*/
|
||||
class ScheduleEntry {
|
||||
public:
|
||||
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)
|
||||
{ }
|
||||
|
||||
/** 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;
|
||||
};
|
||||
|
||||
/** The ResourceSked maintains the complete schedule
|
||||
for an instruction. That schedule includes what
|
||||
resources an instruction wants to acquire at each
|
||||
pipeline stage and is represented by a collection
|
||||
of ScheduleEntry objects (described above) that
|
||||
must be executed in-order.
|
||||
|
||||
In every pipeline stage, the InOrder model will
|
||||
process all entries on the resource schedule for
|
||||
that stage and then send the instruction to the next
|
||||
stage if and only if the instruction successfully
|
||||
completed each ScheduleEntry.
|
||||
*/
|
||||
class ResourceSked {
|
||||
public:
|
||||
typedef std::list<ScheduleEntry*>::iterator SkedIt;
|
||||
typedef std::vector<std::list<ScheduleEntry*> > StageList;
|
||||
|
||||
ResourceSked();
|
||||
|
||||
/** Initializee the current entry pointer to
|
||||
pipeline stage 0 and the 1st schedule entry
|
||||
*/
|
||||
void init();
|
||||
|
||||
/** Goes through the remaining stages on the schedule
|
||||
and sums all the remaining entries left to be
|
||||
processed
|
||||
*/
|
||||
int size();
|
||||
|
||||
/** Is the schedule empty? */
|
||||
bool empty();
|
||||
|
||||
/** Beginning Entry of this schedule */
|
||||
SkedIt begin();
|
||||
|
||||
/** Ending Entry of this schedule */
|
||||
SkedIt end();
|
||||
|
||||
/** Ending Entry of a specified stage */
|
||||
SkedIt end(int stage_num);
|
||||
|
||||
/** Find a schedule entry based on stage and command */
|
||||
SkedIt find(int stage_num, int cmd);
|
||||
|
||||
/** What is the next task for this instruction schedule? */
|
||||
ScheduleEntry* top();
|
||||
|
||||
/** Top() Task is completed, remove it from schedule */
|
||||
void pop();
|
||||
|
||||
/** Add To Schedule based on stage num and priority of
|
||||
Schedule Entry
|
||||
*/
|
||||
void push(ScheduleEntry* sked_entry);
|
||||
|
||||
/** Add Schedule Entry to be in front of another Entry */
|
||||
void pushBefore(ScheduleEntry* sked_entry, int sked_cmd, int sked_cmd_idx);
|
||||
|
||||
/** Print what's left on the instruction schedule */
|
||||
void print();
|
||||
|
||||
StageList *getStages()
|
||||
{
|
||||
return &stages;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Current Schedule Entry Pointer */
|
||||
SkedIt curSkedEntry;
|
||||
|
||||
/** The Stage-by-Stage Resource Schedule:
|
||||
Resized to Number of Stages in the constructor
|
||||
*/
|
||||
StageList stages;
|
||||
|
||||
/** Find a place to insert the instruction using the
|
||||
schedule entries priority
|
||||
*/
|
||||
SkedIt findIterByPriority(ScheduleEntry *sked_entry, int stage_num);
|
||||
|
||||
/** Find a place to insert the instruction using a particular command
|
||||
to look for.
|
||||
*/
|
||||
SkedIt findIterByCommand(ScheduleEntry *sked_entry, int stage_num,
|
||||
int sked_cmd, int sked_cmd_idx = -1);
|
||||
};
|
||||
|
||||
/** Wrapper class around the SkedIt iterator in the Resource Sked so that
|
||||
we can use ++ operator to automatically go to the next available
|
||||
resource schedule entry but otherwise maintain same functionality
|
||||
as a normal iterator.
|
||||
*/
|
||||
class RSkedIt
|
||||
{
|
||||
public:
|
||||
RSkedIt()
|
||||
: curStage(0), numStages(0)
|
||||
{ }
|
||||
|
||||
|
||||
/** init() must be called before the use of any other member
|
||||
in the RSkedIt class.
|
||||
*/
|
||||
void init(ResourceSked* rsked)
|
||||
{
|
||||
stages = rsked->getStages();
|
||||
numStages = stages->size();
|
||||
}
|
||||
|
||||
/* Update the encapsulated "myIt" iterator, but only
|
||||
update curStage/curStage_end if the iterator is valid.
|
||||
The iterator could be invalid in the case where
|
||||
someone is saving the end of a list (i.e. std::list->end())
|
||||
*/
|
||||
RSkedIt operator=(ResourceSked::SkedIt const &rhs)
|
||||
{
|
||||
myIt = rhs;
|
||||
if (myIt != (*stages)[numStages-1].end()) {
|
||||
curStage = (*myIt)->stageNum;
|
||||
curStage_end = (*stages)[curStage].end();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Increment to the next entry in current stage.
|
||||
If no more entries then find the next stage that has
|
||||
resource schedule to complete.
|
||||
If no more stages, then return the end() iterator from
|
||||
the last stage to indicate we are done.
|
||||
*/
|
||||
RSkedIt &operator++(int unused)
|
||||
{
|
||||
if (++myIt == curStage_end) {
|
||||
curStage++;
|
||||
while (curStage < numStages) {
|
||||
if ((*stages)[curStage].empty()) {
|
||||
curStage++;
|
||||
} else {
|
||||
myIt = (*stages)[curStage].begin();
|
||||
curStage_end = (*stages)[curStage].end();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
myIt = (*stages)[numStages - 1].end();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** The "pointer" operator can be used on a RSkedIt and it
|
||||
will use the encapsulated iterator
|
||||
*/
|
||||
ScheduleEntry* operator->()
|
||||
{
|
||||
return *myIt;
|
||||
}
|
||||
|
||||
/** Dereferencing a RSKedIt will access the encapsulated
|
||||
iterator
|
||||
*/
|
||||
ScheduleEntry* operator*()
|
||||
{
|
||||
return *myIt;
|
||||
}
|
||||
|
||||
/** Equality for RSkedIt only compares the "myIt" iterators,
|
||||
as the other members are just ancillary
|
||||
*/
|
||||
bool operator==(RSkedIt const &rhs)
|
||||
{
|
||||
return this->myIt == rhs.myIt;
|
||||
}
|
||||
|
||||
/** Inequality for RSkedIt only compares the "myIt" iterators,
|
||||
as the other members are just ancillary
|
||||
*/
|
||||
bool operator!=(RSkedIt const &rhs)
|
||||
{
|
||||
return this->myIt != rhs.myIt;
|
||||
}
|
||||
|
||||
/* The == and != operator overloads should be sufficient
|
||||
here if need otherwise direct access to the schedule
|
||||
iterator, then this can be used */
|
||||
ResourceSked::SkedIt getIt()
|
||||
{
|
||||
return myIt;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Schedule Iterator that this class is encapsulating */
|
||||
ResourceSked::SkedIt myIt;
|
||||
|
||||
/** Ptr to resource schedule that the 'myIt' iterator
|
||||
belongs to
|
||||
*/
|
||||
ResourceSked::StageList *stages;
|
||||
|
||||
/** The last iterator in the current stage. */
|
||||
ResourceSked::SkedIt curStage_end;
|
||||
|
||||
/** Current Stage that "myIt" refers to. */
|
||||
int curStage;
|
||||
|
||||
/** Number of stages in the "*stages" object. */
|
||||
int numStages;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_RESOURCE_SKED_HH__
|
||||
107
simulators/gem5/src/cpu/inorder/resources/agen_unit.cc
Normal file
107
simulators/gem5/src/cpu/inorder/resources/agen_unit.cc
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "debug/InOrderAGEN.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::regStats()
|
||||
{
|
||||
agens
|
||||
.name(name() + ".agens")
|
||||
.desc("Number of Address Generations");
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
AGENUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* agen_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
#if TRACING_ON
|
||||
ThreadID tid = inst->readTid();
|
||||
#endif
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderAGEN,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
agen_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (agen_req->cmd)
|
||||
{
|
||||
case GenerateAddr:
|
||||
{
|
||||
// Load/Store Instruction
|
||||
if (inst->isMemRef()) {
|
||||
DPRINTF(InOrderAGEN,
|
||||
"[tid:%i] Generating Address for [sn:%i] (%s).\n",
|
||||
tid, seq_num, inst->staticInst->getName());
|
||||
|
||||
inst->fault = inst->calcEA();
|
||||
inst->setMemAddr(inst->getEA());
|
||||
|
||||
DPRINTF(InOrderAGEN,
|
||||
"[tid:%i] [sn:%i] Effective address calculated as: %#x\n",
|
||||
tid, seq_num, inst->getEA());
|
||||
|
||||
if (inst->fault == NoFault) {
|
||||
agen_req->done();
|
||||
} else {
|
||||
fatal("%s encountered while calculating address [sn:%i] %s",
|
||||
inst->fault->name(), seq_num, inst->instName());
|
||||
}
|
||||
|
||||
agens++;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
64
simulators/gem5/src/cpu/inorder/resources/agen_unit.hh
Normal file
64
simulators/gem5/src/cpu/inorder/resources/agen_unit.hh
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_AGEN_UNIT_HH__
|
||||
#define __CPU_INORDER_AGEN_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/params.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class AGENUnit : public Resource {
|
||||
public:
|
||||
typedef InOrderDynInst::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
AGENUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
enum Command {
|
||||
GenerateAddr
|
||||
};
|
||||
|
||||
virtual void execute(int slot_num);
|
||||
void regStats();
|
||||
|
||||
protected:
|
||||
Stats::Scalar agens;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_DECODE_UNIT_HH__
|
||||
464
simulators/gem5/src/cpu/inorder/resources/bpred_unit.cc
Normal file
464
simulators/gem5/src/cpu/inorder/resources/bpred_unit.cc
Normal file
@ -0,0 +1,464 @@
|
||||
|
||||
/*
|
||||
* 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 "arch/utility.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/bpred_unit.hh"
|
||||
#include "debug/InOrderBPred.hh"
|
||||
#include "debug/Resource.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
BPredUnit::BPredUnit(Resource *_res, ThePipeline::Params *params)
|
||||
: res(_res),
|
||||
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);
|
||||
|
||||
instSize = sizeof(TheISA::MachInst);
|
||||
}
|
||||
|
||||
std::string
|
||||
BPredUnit::name()
|
||||
{
|
||||
return res->name();
|
||||
}
|
||||
|
||||
void
|
||||
BPredUnit::regStats()
|
||||
{
|
||||
lookups
|
||||
.name(name() + ".lookups")
|
||||
.desc("Number of BP lookups")
|
||||
;
|
||||
|
||||
condPredicted
|
||||
.name(name() + ".condPredicted")
|
||||
.desc("Number of conditional branches predicted")
|
||||
;
|
||||
|
||||
condIncorrect
|
||||
.name(name() + ".condIncorrect")
|
||||
.desc("Number of conditional branches incorrect")
|
||||
;
|
||||
|
||||
BTBLookups
|
||||
.name(name() + ".BTBLookups")
|
||||
.desc("Number of BTB lookups")
|
||||
;
|
||||
|
||||
BTBHits
|
||||
.name(name() + ".BTBHits")
|
||||
.desc("Number of BTB hits")
|
||||
;
|
||||
|
||||
BTBHitPct
|
||||
.name(name() + ".BTBHitPct")
|
||||
.desc("BTB Hit Percentage")
|
||||
.precision(6);
|
||||
BTBHitPct = (BTBHits / BTBLookups) * 100;
|
||||
|
||||
usedRAS
|
||||
.name(name() + ".usedRAS")
|
||||
.desc("Number of times the RAS was used to get a target.")
|
||||
;
|
||||
|
||||
RASIncorrect
|
||||
.name(name() + ".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, TheISA::PCState &predPC, ThreadID 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;
|
||||
|
||||
int asid = inst->asid;
|
||||
bool pred_taken = false;
|
||||
TheISA::PCState target;
|
||||
|
||||
++lookups;
|
||||
DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
|
||||
"prediction\n", tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(inst->instAddr()),
|
||||
inst->pcState());
|
||||
|
||||
|
||||
void *bp_history = NULL;
|
||||
|
||||
if (inst->isUncondCtrl()) {
|
||||
DPRINTF(InOrderBPred, "[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(InOrderBPred, "[tid:%i] RAS is empty, predicting "
|
||||
"false.\n", tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
} else {
|
||||
++condPredicted;
|
||||
|
||||
pred_taken = BPLookup(predPC.instAddr(), bp_history);
|
||||
}
|
||||
|
||||
PredictorHistory predict_record(inst->seqNum, predPC, 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.
|
||||
TheISA::PCState rasTop = RAS[tid].top();
|
||||
target = TheISA::buildRetPC(inst->pcState(), rasTop);
|
||||
|
||||
// Record the top entry of the RAS, and its index.
|
||||
predict_record.usedRAS = true;
|
||||
predict_record.RASIndex = RAS[tid].topIdx();
|
||||
predict_record.rasTarget = rasTop;
|
||||
|
||||
assert(predict_record.RASIndex < 16);
|
||||
|
||||
RAS[tid].pop();
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: Instruction %s is a return, "
|
||||
"RAS predicted target: %s, RAS index: %i.\n",
|
||||
tid, inst->pcState(), target,
|
||||
predict_record.RASIndex);
|
||||
} else {
|
||||
++BTBLookups;
|
||||
|
||||
if (inst->isCall()) {
|
||||
|
||||
RAS[tid].push(inst->pcState());
|
||||
|
||||
// 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(InOrderBPred, "[tid:%i]: Instruction %s was a call"
|
||||
", adding %s to the RAS index: %i.\n",
|
||||
tid, inst->pcState(), predPC,
|
||||
RAS[tid].topIdx());
|
||||
}
|
||||
|
||||
if (inst->isCall() &&
|
||||
inst->isUncondCtrl() &&
|
||||
inst->isDirectCtrl()) {
|
||||
target = inst->branchTarget();
|
||||
} else if (BTB.valid(predPC.instAddr(), asid)) {
|
||||
++BTBHits;
|
||||
|
||||
// If it's not a return, use the BTB to get the target addr.
|
||||
target = BTB.lookup(predPC.instAddr(), asid);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [asid:%i] Instruction %s "
|
||||
"predicted target is %s.\n",
|
||||
tid, asid, inst->pcState(), target);
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: BTB doesn't have a "
|
||||
"valid entry, predicting false.\n",tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pred_taken) {
|
||||
// Set the PC and the instruction's predicted target.
|
||||
predPC = target;
|
||||
}
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
|
||||
tid, inst->seqNum, predPC);
|
||||
|
||||
predHist[tid].push_front(predict_record);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] pushed onto front of predHist "
|
||||
"...predHist.size(): %i\n",
|
||||
tid, inst->seqNum, predHist[tid].size());
|
||||
|
||||
return pred_taken;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPredUnit::update(const InstSeqNum &done_sn, ThreadID 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.instAddr(),
|
||||
predHist[tid].back().predTaken,
|
||||
predHist[tid].back().bpHistory,
|
||||
false);
|
||||
|
||||
predHist[tid].pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid, ThreadID asid)
|
||||
{
|
||||
History &pred_hist = predHist[tid];
|
||||
|
||||
while (!pred_hist.empty() &&
|
||||
pred_hist.front().seqNum > squashed_sn) {
|
||||
if (pred_hist.front().usedRAS) {
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Restoring top of RAS "
|
||||
"to: %i, target: %s.\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(InOrderBPred, "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 TheISA::PCState &corrTarget,
|
||||
bool actually_taken,
|
||||
ThreadID tid,
|
||||
ThreadID asid)
|
||||
{
|
||||
// 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(InOrderBPred, "[tid:%i]: Squashing from sequence number %i, "
|
||||
"setting target to %s.\n",
|
||||
tid, squashed_sn, corrTarget);
|
||||
|
||||
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()) {
|
||||
HistoryIt hist_it = pred_hist.begin();
|
||||
//HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
|
||||
// squashed_sn);
|
||||
|
||||
//assert(hist_it != pred_hist.end());
|
||||
if (pred_hist.front().seqNum != squashed_sn) {
|
||||
DPRINTF(InOrderBPred, "Front sn %i != Squash sn %i\n",
|
||||
pred_hist.front().seqNum, squashed_sn);
|
||||
|
||||
assert(pred_hist.front().seqNum == squashed_sn);
|
||||
}
|
||||
|
||||
|
||||
if ((*hist_it).usedRAS) {
|
||||
++RASIncorrect;
|
||||
}
|
||||
|
||||
BPUpdate((*hist_it).pc.instAddr(), actually_taken,
|
||||
pred_hist.front().bpHistory, true);
|
||||
|
||||
// only update BTB on branch taken right???
|
||||
if (actually_taken)
|
||||
BTB.update((*hist_it).pc.instAddr(), corrTarget, asid);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: Removing history for [sn:%i] "
|
||||
"PC %s.\n", tid, (*hist_it).seqNum, (*hist_it).pc);
|
||||
|
||||
pred_hist.erase(hist_it);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: predHist.size(): %i\n", tid,
|
||||
predHist[tid].size());
|
||||
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i] pred_hist empty, can't "
|
||||
"update.\n", tid, squashed_sn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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, bool squashed)
|
||||
{
|
||||
if (predictor == Local) {
|
||||
localBP->update(inst_PC, taken, bp_history);
|
||||
} else if (predictor == Tournament) {
|
||||
tournamentBP->update(inst_PC, taken, bp_history, squashed);
|
||||
} 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");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
267
simulators/gem5/src/cpu/inorder/resources/bpred_unit.hh
Normal file
267
simulators/gem5/src/cpu/inorder/resources/bpred_unit.hh
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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__
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/pred/2bit_local.hh"
|
||||
#include "cpu/pred/btb.hh"
|
||||
#include "cpu/pred/ras.hh"
|
||||
#include "cpu/pred/tournament.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
|
||||
/**
|
||||
* 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(Resource *_res, ThePipeline::Params *params);
|
||||
|
||||
std::string name();
|
||||
|
||||
/**
|
||||
* 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 predPC 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,
|
||||
TheISA::PCState &predPC, ThreadID 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, ThreadID 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, ThreadID tid,
|
||||
ThreadID asid = 0);
|
||||
|
||||
/**
|
||||
* 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 corrTarget The correct branch target.
|
||||
* @param actually_taken The correct branch direction.
|
||||
* @param tid The thread id.
|
||||
*/
|
||||
void squash(const InstSeqNum &squashed_sn,
|
||||
const TheISA::PCState &corrTarget, bool actually_taken,
|
||||
ThreadID tid, ThreadID asid = 0);
|
||||
|
||||
/**
|
||||
* @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 instPC, 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.
|
||||
*/
|
||||
TheISA::PCState BTBLookup(Addr instPC)
|
||||
{ return BTB.lookup(instPC, 0); }
|
||||
|
||||
/**
|
||||
* Updates the BP with taken/not taken information.
|
||||
* @param instPC 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.
|
||||
* @param squashed if the branch in question was squashed or not
|
||||
* @todo Make this update flexible enough to handle a global predictor.
|
||||
*/
|
||||
void BPUpdate(Addr instPC, bool taken, void *bp_history, bool squashed);
|
||||
|
||||
/**
|
||||
* 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 instPC, const TheISA::PCState &targetPC)
|
||||
{ BTB.update(instPC, targetPC, 0); }
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
int instSize;
|
||||
Resource *res;
|
||||
|
||||
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 TheISA::PCState &instPC, bool pred_taken,
|
||||
void *bp_history, ThreadID _tid)
|
||||
: seqNum(seq_num), pc(instPC), 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. */
|
||||
TheISA::PCState pc;
|
||||
|
||||
/** The RAS target (only valid if a return). */
|
||||
TheISA::PCState rasTarget;
|
||||
|
||||
/** The RAS index of the instruction (only valid if a call). */
|
||||
unsigned RASIndex;
|
||||
|
||||
/** The thread id. */
|
||||
ThreadID 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;
|
||||
typedef History::iterator HistoryIt;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
Stats::Formula BTBHitPct;
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_BPRED_UNIT_HH__
|
||||
181
simulators/gem5/src/cpu/inorder/resources/branch_predictor.cc
Normal file
181
simulators/gem5/src/cpu/inorder/resources/branch_predictor.cc
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/branch_predictor.hh"
|
||||
#include "debug/InOrderBPred.hh"
|
||||
#include "debug/InOrderStage.hh"
|
||||
#include "debug/Resource.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(this, 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();
|
||||
|
||||
branchPred.regStats();
|
||||
}
|
||||
|
||||
void
|
||||
BranchPredictor::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* bpred_req = reqs[slot_num];
|
||||
DynInstPtr inst = bpred_req->inst;
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderBPred,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
bpred_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inst->isControl()) {
|
||||
DPRINTF(Resource, "Ignoring %s, not a control inst.\n",
|
||||
inst->instName());
|
||||
bpred_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadID tid = inst->readTid();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
switch (bpred_req->cmd)
|
||||
{
|
||||
case PredictBranch:
|
||||
{
|
||||
if (inst->seqNum > cpu->squashSeqNum[tid] &&
|
||||
curTick() == cpu->lastSquashCycle[tid]) {
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, "
|
||||
"skipping prediction \n", tid, inst->seqNum);
|
||||
} else {
|
||||
TheISA::PCState pred_PC = inst->pcState();
|
||||
TheISA::advancePC(pred_PC, inst->staticInst);
|
||||
|
||||
if (inst->isControl()) {
|
||||
// If not, the pred_PC be updated to pc+8
|
||||
// If predicted, the pred_PC will be updated to new target
|
||||
// value
|
||||
bool predict_taken = branchPred.predict(inst, pred_PC, tid);
|
||||
|
||||
if (predict_taken) {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch "
|
||||
"predicted true.\n", tid, seq_num);
|
||||
predictedTaken++;
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch "
|
||||
"predicted false.\n", tid, seq_num);
|
||||
predictedNotTaken++;
|
||||
}
|
||||
|
||||
inst->setBranchPred(predict_taken);
|
||||
}
|
||||
|
||||
//@todo: Check to see how hw_rei is handled here...how does PC,NPC get
|
||||
// updated to compare mispredict against???
|
||||
inst->setPredTarg(pred_PC);
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: %s Predicted PC is "
|
||||
"%s.\n", tid, seq_num, inst->instName(), pred_PC);
|
||||
}
|
||||
|
||||
bpred_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
case UpdatePredictor:
|
||||
{
|
||||
if (inst->seqNum > cpu->squashSeqNum[tid] &&
|
||||
curTick() == cpu->lastSquashCycle[tid]) {
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, "
|
||||
"skipping branch predictor update \n",
|
||||
tid, inst->seqNum);
|
||||
} else {
|
||||
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, ThreadID tid)
|
||||
{
|
||||
InstSeqNum bpred_squash_num = inst->seqNum;
|
||||
DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid,
|
||||
bpred_squash_num);
|
||||
|
||||
// update due to branch resolution
|
||||
if (squash_stage >= ThePipeline::BackEndStartStage) {
|
||||
branchPred.squash(bpred_squash_num,
|
||||
inst->pcState(),
|
||||
inst->pcState().branching(),
|
||||
tid);
|
||||
} else {
|
||||
// update due to predicted taken branch
|
||||
branchPred.squash(bpred_squash_num, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BranchPredictor::instGraduated(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
branchPred.update(seq_num, tid);
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_BRANCH_PREDICTOR_HH__
|
||||
#define __CPU_INORDER_BRANCH_PREDICTOR_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/bpred_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class BranchPredictor : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
enum Command {
|
||||
PredictBranch,
|
||||
UpdatePredictor
|
||||
};
|
||||
|
||||
public:
|
||||
BranchPredictor(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
void regStats();
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void instGraduated(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
protected:
|
||||
/** List of instructions this resource is currently
|
||||
* processing.
|
||||
*/
|
||||
BPredUnit branchPred;
|
||||
|
||||
int instSize;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RESOURCE STATISTICS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Stats::Scalar predictedTaken;
|
||||
Stats::Scalar predictedNotTaken;
|
||||
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
|
||||
1288
simulators/gem5/src/cpu/inorder/resources/cache_unit.cc
Normal file
1288
simulators/gem5/src/cpu/inorder/resources/cache_unit.cc
Normal file
File diff suppressed because it is too large
Load Diff
268
simulators/gem5/src/cpu/inorder/resources/cache_unit.hh
Normal file
268
simulators/gem5/src/cpu/inorder/resources/cache_unit.hh
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/tlb.hh"
|
||||
#include "base/hashmap.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
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);
|
||||
|
||||
enum Command {
|
||||
InitiateReadData,
|
||||
CompleteReadData,
|
||||
InitiateWriteData,
|
||||
CompleteWriteData,
|
||||
InitSecondSplitRead,
|
||||
InitSecondSplitWrite,
|
||||
CompleteSecondSplitRead,
|
||||
CompleteSecondSplitWrite
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
void init();
|
||||
|
||||
ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num,
|
||||
unsigned cmd);
|
||||
|
||||
ResReqPtr findRequest(DynInstPtr inst);
|
||||
ResReqPtr findRequest(DynInstPtr inst, int idx);
|
||||
|
||||
void requestAgain(DynInstPtr inst, bool &try_request);
|
||||
|
||||
virtual int getSlot(DynInstPtr inst);
|
||||
|
||||
/** Executes one of the commands from the "Command" enum */
|
||||
virtual void execute(int slot_num);
|
||||
|
||||
virtual void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
virtual void squashCacheRequest(CacheReqPtr req_ptr);
|
||||
|
||||
/** After memory request is completedd in the cache, then do final
|
||||
processing to complete the request in the CPU.
|
||||
*/
|
||||
virtual void processCacheCompletion(PacketPtr pkt);
|
||||
|
||||
/** Create request that will interface w/TLB and Memory objects */
|
||||
virtual void setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
|
||||
int acc_size, int flags);
|
||||
|
||||
void finishCacheUnitReq(DynInstPtr inst, CacheRequest *cache_req);
|
||||
|
||||
void buildDataPacket(CacheRequest *cache_req);
|
||||
|
||||
bool processSquash(CacheReqPacket *cache_pkt);
|
||||
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
void recvRetry();
|
||||
|
||||
Fault read(DynInstPtr inst, Addr addr,
|
||||
uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
Fault write(DynInstPtr inst, uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
void doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
|
||||
int flags, TheISA::TLB::Mode tlb_mode);
|
||||
|
||||
/** Read/Write on behalf of an instruction.
|
||||
* curResSlot needs to be a valid value in instruction.
|
||||
*/
|
||||
void doCacheAccess(DynInstPtr inst, uint64_t *write_result=NULL,
|
||||
CacheReqPtr split_req=NULL);
|
||||
|
||||
uint64_t getMemData(Packet *packet);
|
||||
|
||||
void setAddrDependency(DynInstPtr inst);
|
||||
virtual void removeAddrDependency(DynInstPtr inst);
|
||||
|
||||
protected:
|
||||
/** Cache interface. */
|
||||
MasterPort *cachePort;
|
||||
|
||||
bool cachePortBlocked;
|
||||
|
||||
std::list<Addr> addrList[ThePipeline::MaxThreads];
|
||||
|
||||
m5::hash_map<Addr, InstSeqNum> addrMap[ThePipeline::MaxThreads];
|
||||
|
||||
public:
|
||||
int cacheBlkSize;
|
||||
|
||||
int cacheBlkMask;
|
||||
|
||||
/** Align a PC to the start of the Cache block. */
|
||||
Addr cacheBlockAlign(Addr addr)
|
||||
{
|
||||
return (addr & ~(cacheBlkMask));
|
||||
}
|
||||
|
||||
bool tlbBlocked[ThePipeline::MaxThreads];
|
||||
InstSeqNum tlbBlockSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
TheISA::TLB* tlb();
|
||||
TheISA::TLB *_tlb;
|
||||
};
|
||||
|
||||
class CacheUnitEvent : public ResourceEvent {
|
||||
public:
|
||||
const std::string name() const
|
||||
{
|
||||
return "CacheUnitEvent";
|
||||
}
|
||||
|
||||
|
||||
/** Constructs a resource event. */
|
||||
CacheUnitEvent();
|
||||
virtual ~CacheUnitEvent() {}
|
||||
|
||||
/** Processes a resource event. */
|
||||
void process();
|
||||
};
|
||||
|
||||
//@todo: Move into CacheUnit Class for private access to "valid" field
|
||||
class CacheRequest : public ResourceRequest
|
||||
{
|
||||
public:
|
||||
CacheRequest(CacheUnit *cres)
|
||||
: ResourceRequest(cres), memReq(NULL), reqData(NULL),
|
||||
dataPkt(NULL), memAccComplete(false),
|
||||
memAccPending(false), tlbStall(false), splitAccess(false),
|
||||
splitAccessNum(-1), split2ndAccess(false),
|
||||
fetchBufferFill(false)
|
||||
{ }
|
||||
|
||||
virtual ~CacheRequest()
|
||||
{
|
||||
if (reqData && !splitAccess)
|
||||
delete [] reqData;
|
||||
}
|
||||
|
||||
void setRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num,
|
||||
unsigned _cmd, MemCmd::Command pkt_cmd, int idx)
|
||||
{
|
||||
pktCmd = pkt_cmd;
|
||||
instIdx = idx;
|
||||
|
||||
ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num, _cmd);
|
||||
}
|
||||
|
||||
void clearRequest();
|
||||
|
||||
virtual PacketDataPtr getData()
|
||||
{ return reqData; }
|
||||
|
||||
void
|
||||
setMemAccCompleted(bool completed = true)
|
||||
{
|
||||
memAccComplete = completed;
|
||||
}
|
||||
|
||||
bool is2ndSplit()
|
||||
{
|
||||
return split2ndAccess;
|
||||
}
|
||||
|
||||
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;
|
||||
CacheReqPacket *dataPkt;
|
||||
|
||||
bool memAccComplete;
|
||||
bool memAccPending;
|
||||
bool tlbStall;
|
||||
|
||||
bool splitAccess;
|
||||
int splitAccessNum;
|
||||
bool split2ndAccess;
|
||||
int instIdx;
|
||||
|
||||
/** Should we expect block from cache access or fetch buffer? */
|
||||
bool fetchBufferFill;
|
||||
};
|
||||
|
||||
class CacheReqPacket : public Packet
|
||||
{
|
||||
public:
|
||||
CacheReqPacket(CacheRequest *_req,
|
||||
Command _cmd, int _idx = 0)
|
||||
: Packet(&(*_req->memReq), _cmd), cacheReq(_req),
|
||||
instIdx(_idx), hasSlot(false), reqData(NULL), memReq(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CacheRequest *cacheReq;
|
||||
int instIdx;
|
||||
bool hasSlot;
|
||||
PacketDataPtr reqData;
|
||||
RequestPtr memReq;
|
||||
};
|
||||
|
||||
#endif //__CPU_CACHE_UNIT_HH__
|
||||
97
simulators/gem5/src/cpu/inorder/resources/decode_unit.cc
Normal file
97
simulators/gem5/src/cpu/inorder/resources/decode_unit.cc
Normal file
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/decode_unit.hh"
|
||||
#include "debug/InOrderDecode.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "debug/Resource.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 (ThreadID tid = 0; tid < MaxThreads; tid++) {
|
||||
regDepMap[tid] = &cpu->archRegDepMap[tid];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DecodeUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* decode_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
|
||||
switch (decode_req->cmd)
|
||||
{
|
||||
case DecodeInst:
|
||||
{
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
inst->setBackSked(cpu->faultSked);
|
||||
DPRINTF(InOrderDecode,"[tid:%i]: Fault found for instruction [sn:%i]\n",
|
||||
inst->readTid(), inst->seqNum);
|
||||
} else {
|
||||
assert(!inst->staticInst->isMacroop());
|
||||
inst->setBackSked(cpu->createBackEndSked(inst));
|
||||
DPRINTF(InOrderDecode,"Decoded instruction [sn:%i]: %s : 0x%x\n",
|
||||
inst->seqNum, inst->instName(),
|
||||
inst->staticInst->machInst);
|
||||
}
|
||||
|
||||
if (inst->backSked != NULL) {
|
||||
DPRINTF(InOrderDecode,
|
||||
"[tid:%i]: Back End Schedule created for %s [sn:%i].\n",
|
||||
inst->readTid(), inst->instName(), inst->seqNum);
|
||||
decode_req->done();
|
||||
} else {
|
||||
DPRINTF(Resource,
|
||||
"[tid:%i] Static Inst not available to decode.\n",
|
||||
inst->readTid());
|
||||
DPRINTF(Resource,
|
||||
"Unable to create schedule for instruction [sn:%i] \n",
|
||||
inst->seqNum);
|
||||
DPRINTF(InOrderStall, "STALL: \n");
|
||||
decode_req->done(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
65
simulators/gem5/src/cpu/inorder/resources/decode_unit.hh
Normal file
65
simulators/gem5/src/cpu/inorder/resources/decode_unit.hh
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "cpu/inorder/resource.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);
|
||||
|
||||
enum Command {
|
||||
DecodeInst
|
||||
};
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
RegDepMap *regDepMap[ThePipeline::MaxThreads];
|
||||
|
||||
protected:
|
||||
/** @todo: Add Resource Stats Here */
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_DECODE_UNIT_HH__
|
||||
249
simulators/gem5/src/cpu/inorder/resources/execution_unit.cc
Normal file
249
simulators/gem5/src/cpu/inorder/resources/execution_unit.cc
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/execution_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/Fault.hh"
|
||||
#include "debug/InOrderExecute.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "sim/full_system.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),
|
||||
lastExecuteTick(0), lastControlTick(0)
|
||||
{ }
|
||||
|
||||
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).");
|
||||
|
||||
executions
|
||||
.name(name() + ".executions")
|
||||
.desc("Number of Instructions Executed.");
|
||||
|
||||
|
||||
predictedIncorrect
|
||||
.name(name() + ".mispredicted")
|
||||
.desc("Number of Branches Incorrectly Predicted");
|
||||
|
||||
predictedCorrect
|
||||
.name(name() + ".predicted")
|
||||
.desc("Number of Branches Incorrectly Predicted");
|
||||
|
||||
mispredictPct
|
||||
.name(name() + ".mispredictPct")
|
||||
.desc("Percentage of Incorrect Branches Predicts")
|
||||
.precision(6);
|
||||
mispredictPct = (predictedIncorrect /
|
||||
(predictedCorrect + predictedIncorrect)) * 100;
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
ExecutionUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* exec_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderExecute,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
exec_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
Fault fault = NoFault;
|
||||
Tick cur_tick = curTick();
|
||||
unsigned stage_num = exec_req->getStageNum();
|
||||
ThreadID tid = inst->readTid();
|
||||
#if TRACING_ON
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
#endif
|
||||
|
||||
switch (exec_req->cmd)
|
||||
{
|
||||
case ExecuteInst:
|
||||
{
|
||||
if (inst->isNop()) {
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] [PC:%s] Ignoring execution"
|
||||
"of %s.\n", inst->readTid(), seq_num, inst->pcState(),
|
||||
inst->instName());
|
||||
inst->setExecuted();
|
||||
exec_req->done();
|
||||
return;
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%s] %s.\n",
|
||||
inst->readTid(), seq_num, inst->pcState(), inst->instName());
|
||||
}
|
||||
|
||||
if (cur_tick != lastExecuteTick) {
|
||||
lastExecuteTick = cur_tick;
|
||||
}
|
||||
|
||||
//@todo: handle address generation here
|
||||
assert(!inst->isMemRef());
|
||||
|
||||
if (inst->isControl()) {
|
||||
if (lastControlTick == cur_tick) {
|
||||
DPRINTF(InOrderExecute, "Can not Execute More than One Control "
|
||||
"Inst Per Cycle. Blocking Request.\n");
|
||||
exec_req->done(false);
|
||||
return;
|
||||
}
|
||||
lastControlTick = curTick();
|
||||
|
||||
// Evaluate Branch
|
||||
fault = inst->execute();
|
||||
|
||||
// Should unconditional control , pc relative count as an
|
||||
// execution??? Probably not.
|
||||
executions++;
|
||||
|
||||
if (fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
if (inst->mispredicted()) {
|
||||
assert(inst->isControl());
|
||||
|
||||
// Set up Squash Generated By this Misprediction
|
||||
TheISA::PCState pc = inst->pcState();
|
||||
TheISA::advancePC(pc, inst->staticInst);
|
||||
inst->setPredTarg(pc);
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i] Squashing from "
|
||||
"stage %i. Redirecting fetch to %s.\n", tid,
|
||||
inst->seqNum, stage_num, pc);
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
|
||||
" misprediction at %s\n", tid, inst->pcState());
|
||||
|
||||
if (inst->predTaken()) {
|
||||
predictedTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
|
||||
"PC %s ... Mispredicts! "
|
||||
"(Prediction: Taken)\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(
|
||||
inst->instAddr()),
|
||||
inst->pcState());
|
||||
} else {
|
||||
predictedNotTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
|
||||
"PC %s ... Mispredicts! "
|
||||
"(Prediction: Not Taken)\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(
|
||||
inst->instAddr()),
|
||||
inst->pcState());
|
||||
}
|
||||
predictedIncorrect++;
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Prediction"
|
||||
"Correct.\n", inst->readTid(), seq_num);
|
||||
predictedCorrect++;
|
||||
}
|
||||
|
||||
exec_req->done();
|
||||
} else {
|
||||
DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
|
||||
inst->readTid(), inst->seqNum, fault->name());
|
||||
inst->fault = fault;
|
||||
exec_req->done();
|
||||
}
|
||||
} else {
|
||||
// Regular ALU instruction
|
||||
fault = inst->execute();
|
||||
executions++;
|
||||
|
||||
if (fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
#if TRACING_ON
|
||||
for (int didx = 0; didx < inst->numDestRegs(); didx++)
|
||||
if (inst->resultType(didx) == InOrderDynInst::Float ||
|
||||
inst->resultType(didx) == InOrderDynInst::FloatBits ||
|
||||
inst->resultType(didx) == InOrderDynInst::Double)
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Dest result %i "
|
||||
"of FP execution is %08f (%x).\n", inst->readTid(),
|
||||
seq_num, didx, inst->readFloatResult(didx),
|
||||
inst->readFloatBitsResult(didx));
|
||||
else
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Dest result %i "
|
||||
"of Int execution is 0x%x.\n", inst->readTid(),
|
||||
seq_num, didx, inst->readIntResult(didx));
|
||||
#endif
|
||||
|
||||
if (!FullSystem) {
|
||||
// The Syscall might change the PC, so conservatively
|
||||
// squash everything behing it
|
||||
if (inst->isSyscall()) {
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: had a %s "
|
||||
"fault.\n", inst->readTid(), seq_num, fault->name());
|
||||
DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
|
||||
inst->readTid(), inst->seqNum, fault->name());
|
||||
inst->fault = fault;
|
||||
}
|
||||
|
||||
exec_req->done();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
82
simulators/gem5/src/cpu/inorder/resources/execution_unit.hh
Normal file
82
simulators/gem5/src/cpu/inorder/resources/execution_unit.hh
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_EXECUTION_UNIT_HH__
|
||||
#define __CPU_INORDER_EXECUTION_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
|
||||
class ExecutionUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
enum Command {
|
||||
ExecuteInst
|
||||
};
|
||||
|
||||
public:
|
||||
ExecutionUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
public:
|
||||
void regStats();
|
||||
|
||||
/** Execute the function of this resource. The Default is action
|
||||
* is to do nothing. More specific models will derive from this
|
||||
* class and define their own execute function.
|
||||
*/
|
||||
void execute(int slot_num);
|
||||
|
||||
protected:
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RESOURCE STATISTICS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Stats::Scalar predictedTakenIncorrect;
|
||||
Stats::Scalar predictedNotTakenIncorrect;
|
||||
Stats::Scalar predictedIncorrect;
|
||||
Stats::Scalar predictedCorrect;
|
||||
Stats::Formula mispredictPct;
|
||||
Stats::Scalar executions;
|
||||
Tick lastExecuteTick;
|
||||
Tick lastControlTick;
|
||||
};
|
||||
|
||||
|
||||
#endif //__CPU_INORDER_EXCUTION_UNIT_HH__
|
||||
335
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.cc
Normal file
335
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.cc
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/fetch_seq_unit.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/InOrderFetchSeq.hh"
|
||||
#include "debug/InOrderStall.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 (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = 0;
|
||||
|
||||
//@todo: Use CPU's squashSeqNum here instead of maintaining our own
|
||||
// state
|
||||
squashSeqNum[tid] = (InstSeqNum)-1;
|
||||
lastSquashCycle[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FetchSeqUnit::~FetchSeqUnit()
|
||||
{
|
||||
delete [] resourceEvent;
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::init()
|
||||
{
|
||||
resourceEvent = new FetchSeqEvent[width];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new ResourceRequest(this);
|
||||
}
|
||||
|
||||
initSlots();
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* fs_req = reqs[slot_num];
|
||||
DynInstPtr inst = fs_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = fs_req->getStageNum();
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderFetchSeq,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
fs_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fs_req->cmd)
|
||||
{
|
||||
case AssignNextPC:
|
||||
{
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Current PC is %s\n", tid,
|
||||
pc[tid]);
|
||||
|
||||
if (pcValid[tid]) {
|
||||
inst->pcState(pc[tid]);
|
||||
inst->setMemAddr(pc[tid].instAddr());
|
||||
|
||||
// Advance to next PC (typically PC + 4)
|
||||
pc[tid].advance();
|
||||
|
||||
inst->setSeqNum(cpu->getAndIncrementInstSeq(tid));
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to "
|
||||
"PC %s\n", tid, inst->seqNum, inst->pcState());
|
||||
|
||||
fs_req->done();
|
||||
} else {
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid);
|
||||
fs_req->done(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case UpdateTargetPC:
|
||||
{
|
||||
assert(!inst->isCondDelaySlot() &&
|
||||
"Not Handling Conditional Delay Slot");
|
||||
|
||||
if (inst->isControl()) {
|
||||
if (inst->isReturn() && !inst->predTaken()) {
|
||||
// If it's a return, then we must wait for resolved address.
|
||||
// The Predictor will mark a return a false as "not taken"
|
||||
// if there is no RAS entry
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting block signal "
|
||||
"for stage %i.\n",
|
||||
tid, stage_num);
|
||||
cpu->pipelineStage[stage_num]->
|
||||
toPrevStages->stageBlock[stage_num][tid] = true;
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = stage_num;
|
||||
} else if (inst->predTaken()) {
|
||||
// Taken Control
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
|
||||
"start from stage %i, after [sn:%i].\n",
|
||||
tid, stage_num, inst->squashSeqNum);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from %s (%s) "
|
||||
"stage %i.\n", tid, inst->instName(), inst->pcState(),
|
||||
squash_stage);
|
||||
|
||||
if (lastSquashCycle[tid] == curTick() &&
|
||||
squashSeqNum[tid] <= squash_seq_num) {
|
||||
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] = squash_seq_num;
|
||||
lastSquashCycle[tid] = curTick();
|
||||
|
||||
if (inst->staticInst) {
|
||||
if (inst->fault != NoFault) {
|
||||
// A Trap Caused This Fault and will update the pc state
|
||||
// when done trapping
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i] Blocking due to fault @ "
|
||||
"[sn:%i].%s %s \n", inst->seqNum,
|
||||
inst->instName(), inst->pcState());
|
||||
pcValid[tid] = false;
|
||||
} else {
|
||||
TheISA::PCState nextPC;
|
||||
assert(inst->staticInst);
|
||||
if (inst->isControl()) {
|
||||
nextPC = inst->readPredTarg();
|
||||
|
||||
// If we are already fetching this PC then advance to next PC
|
||||
// =======
|
||||
// This should handle ISAs w/delay slots and annulled delay
|
||||
// slots to figure out which is the next PC to fetch after
|
||||
// a mispredict
|
||||
DynInstPtr bdelay_inst = NULL;
|
||||
ListIt bdelay_it;
|
||||
if (inst->onInstList) {
|
||||
bdelay_it = inst->getInstListIt();
|
||||
bdelay_it++;
|
||||
} else {
|
||||
InstSeqNum branch_delay_num = inst->seqNum + 1;
|
||||
bdelay_it = cpu->findInst(branch_delay_num, tid);
|
||||
}
|
||||
|
||||
if (bdelay_it != cpu->instList[tid].end()) {
|
||||
bdelay_inst = (*bdelay_it);
|
||||
}
|
||||
|
||||
if (bdelay_inst) {
|
||||
if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
|
||||
bdelay_inst->pc = nextPC;
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
DPRINTF(InOrderFetchSeq, "Advanced PC to %s\n", nextPC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextPC = inst->pcState();
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
}
|
||||
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
|
||||
tid, nextPC);
|
||||
pc[tid] = nextPC;
|
||||
|
||||
// Unblock Any Stages Waiting for this information to be updated ...
|
||||
if (!pcValid[tid]) {
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting unblock signal "
|
||||
"for stage %i.\n",
|
||||
tid, pcBlockStage[tid]);
|
||||
|
||||
// Need to use "fromNextStages" instead of "toPrevStages"
|
||||
// because the timebuffer will have already have advanced
|
||||
// in the tick function and this squash function will happen after
|
||||
// the tick
|
||||
cpu->pipelineStage[pcBlockStage[tid]]->
|
||||
fromNextStages->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->pcState(i);
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC: %s.\n",
|
||||
fs_res->pc[i]);
|
||||
|
||||
fs_res->pcValid[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FetchSeqUnit::activateThread(ThreadID tid)
|
||||
{
|
||||
pcValid[tid] = true;
|
||||
|
||||
pc[tid] = cpu->pcState(tid);
|
||||
|
||||
cpu->fetchPriorityList.push_back(tid);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC: %s.\n",
|
||||
tid, pc[tid]);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::deactivateThread(ThreadID tid)
|
||||
{
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = 0;
|
||||
|
||||
squashSeqNum[tid] = (InstSeqNum)-1;
|
||||
lastSquashCycle[tid] = 0;
|
||||
|
||||
list<ThreadID>::iterator thread_it = find(cpu->fetchPriorityList.begin(),
|
||||
cpu->fetchPriorityList.end(),
|
||||
tid);
|
||||
|
||||
if (thread_it != cpu->fetchPriorityList.end())
|
||||
cpu->fetchPriorityList.erase(thread_it);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::suspendThread(ThreadID tid)
|
||||
{
|
||||
deactivateThread(tid);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
pcValid[tid] = true;
|
||||
pc[tid] = cpu->pcState(tid);
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Trap updating to PC: "
|
||||
"%s.\n", tid, pc[tid]);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
|
||||
{
|
||||
pcValid[tid] = true;
|
||||
|
||||
if (cpu->thread[tid]->lastGradIsBranch) {
|
||||
/** This function assumes that the instruction causing the context
|
||||
* switch was right after the branch. Thus, if it's not, then
|
||||
* we are updating incorrectly here
|
||||
*/
|
||||
assert(cpu->nextInstAddr(tid) == inst->instAddr());
|
||||
pc[tid] = cpu->thread[tid]->lastBranchPC;
|
||||
} else {
|
||||
pc[tid] = inst->pcState();
|
||||
}
|
||||
assert(inst->staticInst);
|
||||
advancePC(pc[tid], inst->staticInst);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating PCs due to Context Switch."
|
||||
"Assigning PC: %s.\n", tid, pc[tid]);
|
||||
}
|
||||
104
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.hh
Normal file
104
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.hh
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_FETCH_SEQ_UNIT_HH__
|
||||
#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class FetchSeqUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef std::list<DynInstPtr>::iterator ListIt;
|
||||
|
||||
enum Command {
|
||||
AssignNextPC,
|
||||
UpdateTargetPC
|
||||
};
|
||||
|
||||
public:
|
||||
FetchSeqUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
~FetchSeqUnit();
|
||||
|
||||
void init();
|
||||
void activateThread(ThreadID tid);
|
||||
void deactivateThread(ThreadID tid);
|
||||
void suspendThread(ThreadID tid);
|
||||
void execute(int slot_num);
|
||||
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
|
||||
/** Update to correct PC from a squash */
|
||||
void squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Update to correct PC from a trap */
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
protected:
|
||||
unsigned instSize;
|
||||
|
||||
bool pcValid[ThePipeline::MaxThreads];
|
||||
int pcBlockStage[ThePipeline::MaxThreads];
|
||||
|
||||
TheISA::PCState pc[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();
|
||||
~FetchSeqEvent() {}
|
||||
|
||||
/** Processes a resource event. */
|
||||
void process();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
592
simulators/gem5/src/cpu/inorder/resources/fetch_unit.cc
Normal file
592
simulators/gem5/src/cpu/inorder/resources/fetch_unit.cc
Normal file
@ -0,0 +1,592 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/locked_mem.hh"
|
||||
#include "arch/utility.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/cache_unit.hh"
|
||||
#include "cpu/inorder/resources/fetch_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/Activity.hh"
|
||||
#include "debug/InOrderCachePort.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "debug/RefCount.hh"
|
||||
#include "debug/ThreadModel.hh"
|
||||
#include "mem/request.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
using namespace ThePipeline;
|
||||
|
||||
FetchUnit::FetchUnit(string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu,
|
||||
ThePipeline::Params *params)
|
||||
: CacheUnit(res_name, res_id, res_width, res_latency, _cpu, params),
|
||||
instSize(sizeof(TheISA::MachInst)), fetchBuffSize(params->fetchBuffSize)
|
||||
{
|
||||
for (int tid = 0; tid < MaxThreads; tid++)
|
||||
decoder[tid] = new Decoder(NULL);
|
||||
}
|
||||
|
||||
FetchUnit::~FetchUnit()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
while (fetch_it != end_it) {
|
||||
delete (*fetch_it)->block;
|
||||
delete *fetch_it;
|
||||
fetch_it++;
|
||||
}
|
||||
fetchBuffer.clear();
|
||||
|
||||
|
||||
std::list<FetchBlock*>::iterator pend_it = pendingFetch.begin();
|
||||
std::list<FetchBlock*>::iterator pend_end = pendingFetch.end();
|
||||
while (pend_it != pend_end) {
|
||||
if ((*pend_it)->block) {
|
||||
delete (*pend_it)->block;
|
||||
}
|
||||
|
||||
delete *pend_it;
|
||||
pend_it++;
|
||||
}
|
||||
pendingFetch.clear();
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::createMachInst(std::list<FetchBlock*>::iterator fetch_it,
|
||||
DynInstPtr inst)
|
||||
{
|
||||
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
Addr fetch_addr = inst->getMemAddr();
|
||||
unsigned fetch_offset = (fetch_addr - block_addr) / instSize;
|
||||
ThreadID tid = inst->readTid();
|
||||
TheISA::PCState instPC = inst->pcState();
|
||||
|
||||
|
||||
DPRINTF(InOrderCachePort, "Creating instruction [sn:%i] w/fetch data @"
|
||||
"addr:%08p block:%08p\n", inst->seqNum, fetch_addr, block_addr);
|
||||
|
||||
assert((*fetch_it)->valid);
|
||||
|
||||
TheISA::MachInst *fetchInsts =
|
||||
reinterpret_cast<TheISA::MachInst *>((*fetch_it)->block);
|
||||
|
||||
MachInst mach_inst =
|
||||
TheISA::gtoh(fetchInsts[fetch_offset]);
|
||||
|
||||
decoder[tid]->setTC(cpu->thread[tid]->getTC());
|
||||
decoder[tid]->moreBytes(instPC, inst->instAddr(), mach_inst);
|
||||
assert(decoder[tid]->instReady());
|
||||
inst->setStaticInst(decoder[tid]->decode(instPC));
|
||||
inst->pcState(instPC);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::removeAddrDependency(DynInstPtr inst)
|
||||
{
|
||||
inst->unsetMemAddr();
|
||||
}
|
||||
|
||||
ResReqPtr
|
||||
FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
|
||||
int slot_num, unsigned cmd)
|
||||
{
|
||||
ScheduleEntry* sched_entry = *inst->curSkedEntry;
|
||||
CacheRequest* cache_req = dynamic_cast<CacheRequest*>(reqs[slot_num]);
|
||||
|
||||
if (!inst->validMemAddr()) {
|
||||
panic("Mem. Addr. must be set before requesting cache access\n");
|
||||
}
|
||||
|
||||
assert(sched_entry->cmd == InitiateFetch);
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: Fetch request from [sn:%i] for addr %08p\n",
|
||||
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
||||
|
||||
cache_req->setRequest(inst, stage_num, id, slot_num,
|
||||
sched_entry->cmd, MemCmd::ReadReq,
|
||||
inst->curSkedEntry->idx);
|
||||
|
||||
return cache_req;
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
|
||||
int acc_size, int flags)
|
||||
{
|
||||
ThreadID tid = inst->readTid();
|
||||
Addr aligned_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
if (cache_req->memReq == NULL) {
|
||||
cache_req->memReq =
|
||||
new Request(tid, aligned_addr, acc_size, flags,
|
||||
cpu->instMasterId(), inst->instAddr(), cpu->readCpuId(),
|
||||
tid);
|
||||
DPRINTF(InOrderCachePort, "[sn:%i] Created memReq @%x, ->%x\n",
|
||||
inst->seqNum, &cache_req->memReq, cache_req->memReq);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<FetchUnit::FetchBlock*>::iterator
|
||||
FetchUnit::findBlock(std::list<FetchBlock*> &fetch_blocks, int asid,
|
||||
Addr block_addr)
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetch_blocks.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetch_blocks.end();
|
||||
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->asid == asid &&
|
||||
(*fetch_it)->addr == block_addr) {
|
||||
return fetch_it;
|
||||
}
|
||||
|
||||
fetch_it++;
|
||||
}
|
||||
|
||||
return fetch_it;
|
||||
}
|
||||
|
||||
std::list<FetchUnit::FetchBlock*>::iterator
|
||||
FetchUnit::findReplacementBlock()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->cnt == 0) {
|
||||
return fetch_it;
|
||||
} else {
|
||||
DPRINTF(InOrderCachePort, "Block %08p has %i insts pending.\n",
|
||||
(*fetch_it)->addr, (*fetch_it)->cnt);
|
||||
}
|
||||
fetch_it++;
|
||||
}
|
||||
|
||||
return fetch_it;
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::markBlockUsed(std::list<FetchBlock*>::iterator block_it)
|
||||
{
|
||||
// Move block from whatever location it is in fetch buffer
|
||||
// to the back (represents most-recently-used location)
|
||||
if (block_it != fetchBuffer.end()) {
|
||||
FetchBlock *mru_blk = *block_it;
|
||||
fetchBuffer.erase(block_it);
|
||||
fetchBuffer.push_back(mru_blk);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
FetchUnit::blocksInUse()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
|
||||
int cnt = 0;
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->cnt > 0)
|
||||
cnt++;
|
||||
|
||||
fetch_it++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::clearFetchBuffer()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->block) {
|
||||
delete [] (*fetch_it)->block;
|
||||
}
|
||||
delete *fetch_it;
|
||||
fetch_it++;
|
||||
}
|
||||
fetchBuffer.clear();
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::execute(int slot_num)
|
||||
{
|
||||
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqs[slot_num]);
|
||||
assert(cache_req);
|
||||
|
||||
if (cachePortBlocked && cache_req->cmd == InitiateFetch) {
|
||||
DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n");
|
||||
cache_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DynInstPtr inst = cache_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
int asid = cpu->asid[tid];
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
cacheBlockAlign(inst->getMemAddr()));
|
||||
finishCacheUnitReq(inst, cache_req);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cache_req->cmd)
|
||||
{
|
||||
case InitiateFetch:
|
||||
{
|
||||
// Check to see if we've already got this request buffered
|
||||
// or pending to be buffered
|
||||
bool do_fetch = true;
|
||||
int total_pending = pendingFetch.size() + blocksInUse();
|
||||
|
||||
std::list<FetchBlock*>::iterator pending_it;
|
||||
pending_it = findBlock(pendingFetch, asid, block_addr);
|
||||
if (pending_it != pendingFetch.end()) {
|
||||
(*pending_it)->cnt++;
|
||||
do_fetch = false;
|
||||
|
||||
DPRINTF(InOrderCachePort, "%08p is a pending fetch block "
|
||||
"(pending:%i).\n", block_addr,
|
||||
(*pending_it)->cnt);
|
||||
} else if (total_pending < fetchBuffSize) {
|
||||
std::list<FetchBlock*>::iterator buff_it;
|
||||
buff_it = findBlock(fetchBuffer, asid, block_addr);
|
||||
if (buff_it != fetchBuffer.end()) {
|
||||
(*buff_it)->cnt++;
|
||||
do_fetch = false;
|
||||
|
||||
DPRINTF(InOrderCachePort, "%08p is in fetch buffer "
|
||||
"(pending:%i).\n", block_addr, (*buff_it)->cnt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_fetch) {
|
||||
DPRINTF(InOrderCachePort, "Inst. [sn:%i] marked to be filled "
|
||||
"through fetch buffer.\n", inst->seqNum);
|
||||
cache_req->fetchBufferFill = true;
|
||||
cache_req->setCompleted(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if there is room in the fetchbuffer for this instruction.
|
||||
// If not, block this request.
|
||||
if (total_pending >= fetchBuffSize) {
|
||||
DPRINTF(InOrderCachePort, "No room available in fetch buffer.\n");
|
||||
cache_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
doTLBAccess(inst, cache_req, cacheBlkSize, Request::INST_FETCH, TheISA::TLB::Execute);
|
||||
|
||||
if (inst->fault == NoFault) {
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%u]: Initiating fetch access to %s for "
|
||||
"addr:%#x (block:%#x)\n", tid, name(),
|
||||
cache_req->inst->getMemAddr(), block_addr);
|
||||
|
||||
cache_req->reqData = new uint8_t[cacheBlkSize];
|
||||
|
||||
inst->setCurResSlot(slot_num);
|
||||
|
||||
doCacheAccess(inst);
|
||||
|
||||
if (cache_req->isMemAccPending()) {
|
||||
pendingFetch.push_back(new FetchBlock(asid, block_addr));
|
||||
|
||||
// mark replacement block
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CompleteFetch:
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
inst->getMemAddr());
|
||||
finishCacheUnitReq(inst, cache_req);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache_req->fetchBufferFill) {
|
||||
// Block request if it's depending on a previous fetch, but it hasnt made it yet
|
||||
std::list<FetchBlock*>::iterator fetch_it = findBlock(fetchBuffer, asid, block_addr);
|
||||
if (fetch_it == fetchBuffer.end()) {
|
||||
DPRINTF(InOrderCachePort, "%#x not available yet\n",
|
||||
block_addr);
|
||||
cache_req->setCompleted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make New Instruction
|
||||
createMachInst(fetch_it, inst);
|
||||
if (inst->traceData) {
|
||||
inst->traceData->setStaticInst(inst->staticInst);
|
||||
inst->traceData->setPC(inst->pcState());
|
||||
}
|
||||
|
||||
// FetchBuffer Book-Keeping
|
||||
(*fetch_it)->cnt--;
|
||||
assert((*fetch_it)->cnt >= 0);
|
||||
markBlockUsed(fetch_it);
|
||||
|
||||
cache_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache_req->isMemAccComplete()) {
|
||||
if (fetchBuffer.size() >= fetchBuffSize) {
|
||||
// If there is no replacement block, then we'll just have
|
||||
// to wait till that gets cleared before satisfying the fetch
|
||||
// for this instruction
|
||||
std::list<FetchBlock*>::iterator repl_it =
|
||||
findReplacementBlock();
|
||||
if (repl_it == fetchBuffer.end()) {
|
||||
DPRINTF(InOrderCachePort, "Unable to find replacement block"
|
||||
" and complete fetch.\n");
|
||||
cache_req->setCompleted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
delete [] (*repl_it)->block;
|
||||
delete *repl_it;
|
||||
fetchBuffer.erase(repl_it);
|
||||
}
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: Completing Fetch Access for [sn:%i]\n",
|
||||
tid, inst->seqNum);
|
||||
|
||||
// Make New Instruction
|
||||
std::list<FetchBlock*>::iterator fetch_it =
|
||||
findBlock(pendingFetch, asid, block_addr);
|
||||
|
||||
assert(fetch_it != pendingFetch.end());
|
||||
assert((*fetch_it)->valid);
|
||||
|
||||
createMachInst(fetch_it, inst);
|
||||
if (inst->traceData) {
|
||||
inst->traceData->setStaticInst(inst->staticInst);
|
||||
inst->traceData->setPC(inst->pcState());
|
||||
}
|
||||
|
||||
|
||||
// Update instructions waiting on new fetch block
|
||||
FetchBlock *new_block = (*fetch_it);
|
||||
new_block->cnt--;
|
||||
assert(new_block->cnt >= 0);
|
||||
|
||||
// Finally, update FetchBuffer w/Pending Block into the
|
||||
// MRU location
|
||||
pendingFetch.erase(fetch_it);
|
||||
fetchBuffer.push_back(new_block);
|
||||
|
||||
DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(inst->instAddr()));
|
||||
|
||||
inst->unsetMemAddr();
|
||||
|
||||
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->instAddr());
|
||||
cache_req->setCompleted(false);
|
||||
// NOTE: For SwitchOnCacheMiss ThreadModel, we *don't* switch on
|
||||
// fetch miss, but we could ...
|
||||
// cache_req->setMemStall(true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::processCacheCompletion(PacketPtr pkt)
|
||||
{
|
||||
// Cast to correct packet type
|
||||
// @todo: use pkt Sender state here to be consistent with other
|
||||
// cpu models
|
||||
CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
|
||||
assert(cache_pkt);
|
||||
|
||||
DPRINTF(InOrderCachePort, "Finished request for %x\n",
|
||||
cache_pkt->getAddr());
|
||||
|
||||
if (processSquash(cache_pkt))
|
||||
return;
|
||||
|
||||
Addr block_addr = cacheBlockAlign(cache_pkt->cacheReq->
|
||||
getInst()->getMemAddr());
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%u]: [sn:%i]: Waking from fetch access to addr:%#x(phys:%#x), size:%i\n",
|
||||
cache_pkt->cacheReq->getInst()->readTid(),
|
||||
cache_pkt->cacheReq->getInst()->seqNum,
|
||||
block_addr, cache_pkt->getAddr(), cache_pkt->getSize());
|
||||
|
||||
// Cast to correct request type
|
||||
CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
|
||||
findRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx));
|
||||
|
||||
if (!cache_req) {
|
||||
panic("[tid:%u]: [sn:%i]: Can't find slot for fetch access to "
|
||||
"addr. %08p\n", cache_pkt->cacheReq->getInst()->readTid(),
|
||||
cache_pkt->cacheReq->getInst()->seqNum,
|
||||
block_addr);
|
||||
}
|
||||
|
||||
// Get resource request info
|
||||
unsigned stage_num = cache_req->getStageNum();
|
||||
DynInstPtr inst = cache_req->inst;
|
||||
ThreadID tid = cache_req->inst->readTid();
|
||||
short asid = cpu->asid[tid];
|
||||
|
||||
assert(!cache_req->isSquashed());
|
||||
assert(inst->curSkedEntry->cmd == CompleteFetch);
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%u]: [sn:%i]: Processing fetch access for block %#x\n",
|
||||
tid, inst->seqNum, block_addr);
|
||||
|
||||
std::list<FetchBlock*>::iterator pend_it = findBlock(pendingFetch, asid,
|
||||
block_addr);
|
||||
assert(pend_it != pendingFetch.end());
|
||||
|
||||
// Copy Data to pendingFetch queue...
|
||||
(*pend_it)->block = new uint8_t[cacheBlkSize];
|
||||
memcpy((*pend_it)->block, cache_pkt->getPtr<uint8_t>(), cacheBlkSize);
|
||||
(*pend_it)->valid = true;
|
||||
|
||||
cache_req->setMemAccPending(false);
|
||||
cache_req->setMemAccCompleted();
|
||||
|
||||
if (cache_req->isMemStall() &&
|
||||
cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) {
|
||||
DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n",
|
||||
tid);
|
||||
|
||||
cpu->activateContext(tid);
|
||||
|
||||
DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache"
|
||||
"miss.\n", tid);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::squashCacheRequest(CacheReqPtr req_ptr)
|
||||
{
|
||||
DynInstPtr inst = req_ptr->getInst();
|
||||
ThreadID tid = inst->readTid();
|
||||
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
int asid = cpu->asid[tid];
|
||||
|
||||
// Check Fetch Buffer (or pending fetch) for this block and
|
||||
// update pending counts
|
||||
std::list<FetchBlock*>::iterator buff_it = findBlock(fetchBuffer,
|
||||
asid,
|
||||
block_addr);
|
||||
if (buff_it != fetchBuffer.end()) {
|
||||
(*buff_it)->cnt--;
|
||||
DPRINTF(InOrderCachePort, "[sn:%i] Removing Pending Access "
|
||||
"for Fetch Buffer block %08p (cnt=%i)\n", inst->seqNum,
|
||||
block_addr, (*buff_it)->cnt);
|
||||
assert((*buff_it)->cnt >= 0);
|
||||
} else {
|
||||
std::list<FetchBlock*>::iterator block_it = findBlock(pendingFetch,
|
||||
asid,
|
||||
block_addr);
|
||||
if (block_it != pendingFetch.end()) {
|
||||
(*block_it)->cnt--;
|
||||
DPRINTF(InOrderCachePort, "[sn:%i] Removing Pending Access "
|
||||
"for Pending Buffer Block %08p (cnt=%i)\n",
|
||||
inst->seqNum,
|
||||
block_addr, (*block_it)->cnt);
|
||||
assert((*block_it)->cnt >= 0);
|
||||
if ((*block_it)->cnt == 0) {
|
||||
if ((*block_it)->block) {
|
||||
delete [] (*block_it)->block;
|
||||
}
|
||||
delete *block_it;
|
||||
pendingFetch.erase(block_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CacheUnit::squashCacheRequest(req_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
//@todo: per thread?
|
||||
decoder[tid]->reset();
|
||||
|
||||
//@todo: squash using dummy inst seq num
|
||||
squash(NULL, NumStages - 1, 0, tid);
|
||||
|
||||
//@todo: make sure no blocks are in use
|
||||
assert(blocksInUse() == 0);
|
||||
assert(pendingFetch.size() == 0);
|
||||
|
||||
//@todo: clear pendingFetch and fetchBuffer
|
||||
clearFetchBuffer();
|
||||
}
|
||||
138
simulators/gem5/src/cpu/inorder/resources/fetch_unit.hh
Normal file
138
simulators/gem5/src/cpu/inorder/resources/fetch_unit.hh
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_FETCH_UNIT_HH__
|
||||
#define __CPU_INORDER_FETCH_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/decoder.hh"
|
||||
#include "arch/tlb.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/cache_unit.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class FetchUnit : public CacheUnit
|
||||
{
|
||||
public:
|
||||
FetchUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
virtual ~FetchUnit();
|
||||
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef TheISA::ExtMachInst ExtMachInst;
|
||||
|
||||
struct FetchBlock {
|
||||
int asid;
|
||||
Addr addr;
|
||||
uint8_t *block;
|
||||
short cnt;
|
||||
bool valid;
|
||||
|
||||
FetchBlock(int _asid, Addr _addr)
|
||||
: asid(_asid), addr(_addr), block(NULL), cnt(1), valid(false)
|
||||
{ }
|
||||
};
|
||||
|
||||
/** Actions that this resource can take on an instruction */
|
||||
enum Command {
|
||||
InitiateFetch,
|
||||
CompleteFetch
|
||||
};
|
||||
|
||||
|
||||
ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num,
|
||||
unsigned cmd);
|
||||
|
||||
/** Executes one of the commands from the "Command" enum */
|
||||
void execute(int slot_num);
|
||||
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
TheISA::Decoder *decoder[ThePipeline::MaxThreads];
|
||||
|
||||
private:
|
||||
void squashCacheRequest(CacheReqPtr req_ptr);
|
||||
|
||||
void createMachInst(std::list<FetchBlock*>::iterator fetch_it,
|
||||
DynInstPtr inst);
|
||||
|
||||
/** After memory request is completed, then turn the fetched data
|
||||
into an instruction.
|
||||
*/
|
||||
void processCacheCompletion(PacketPtr pkt);
|
||||
|
||||
/** Create request that will interface w/TLB and Memory objects */
|
||||
virtual void setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
|
||||
int acc_size, int flags);
|
||||
|
||||
/** Align a PC to the start of an I-cache block. */
|
||||
Addr cacheBlockAlignPC(Addr addr)
|
||||
{
|
||||
return (addr & ~(cacheBlkMask));
|
||||
}
|
||||
|
||||
void removeAddrDependency(DynInstPtr inst);
|
||||
|
||||
std::list<FetchBlock*>::iterator findReplacementBlock();
|
||||
std::list<FetchBlock*>::iterator findBlock(std::list<FetchBlock*>
|
||||
&fetch_blocks, int asid,
|
||||
Addr block_addr);
|
||||
|
||||
void markBlockUsed(std::list<FetchBlock*>::iterator block_it);
|
||||
|
||||
int blocksInUse();
|
||||
|
||||
void clearFetchBuffer();
|
||||
|
||||
int instSize;
|
||||
|
||||
int fetchBuffSize;
|
||||
|
||||
/** Valid Cache Blocks*/
|
||||
std::list<FetchBlock*> fetchBuffer;
|
||||
|
||||
/** Cache lines that are pending */
|
||||
std::list<FetchBlock*> pendingFetch;
|
||||
};
|
||||
|
||||
#endif //__CPU_FETCH_UNIT_HH__
|
||||
135
simulators/gem5/src/cpu/inorder/resources/graduation_unit.cc
Normal file
135
simulators/gem5/src/cpu/inorder/resources/graduation_unit.cc
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "debug/InOrderGraduation.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)
|
||||
{
|
||||
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
|
||||
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
|
||||
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
|
||||
lastNonSpecTick[tid] = 0;
|
||||
lastFaultTick[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GraduationUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* grad_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = inst->curSkedEntry->stageNum;
|
||||
Tick cur_tick = curTick();
|
||||
|
||||
//@todo: not the common case, anyway we can move this
|
||||
// check to the stage and just ignore instructions
|
||||
// after?
|
||||
if (lastNonSpecTick[tid] == cur_tick) {
|
||||
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
|
||||
"Only 1 nonspec inst. per cycle can graduate.\n");
|
||||
grad_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//@todo: use trap Pending
|
||||
if (cpu->trapPending[tid]) {
|
||||
//if (lastFaultTick[tid] == cur_tick) {
|
||||
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
|
||||
"Only 1 fault can be handled per tick.\n");
|
||||
grad_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (grad_req->cmd)
|
||||
{
|
||||
case CheckFault:
|
||||
{
|
||||
// Handle Any Faults Before Graduating Instruction
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderGraduation, "[tid:%i]: [sn:%i]: fault %s found for %s\n",
|
||||
tid, inst->seqNum, inst->fault->name(),
|
||||
inst->instName());
|
||||
squashThenTrap(stage_num, inst);
|
||||
lastFaultTick[tid] = cur_tick;
|
||||
grad_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF(InOrderGraduation, "[tid:%i] [sn:%i]: No fault found for %s\n",
|
||||
tid, inst->seqNum, inst->instName());
|
||||
grad_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
case GraduateInst:
|
||||
{
|
||||
DPRINTF(InOrderGraduation,
|
||||
"[tid:%i]:[sn:%i]: Graduating instruction %s.\n",
|
||||
tid, inst->seqNum, inst->staticInst->disassemble(inst->instAddr()));
|
||||
|
||||
// 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.
|
||||
// Maybe it should be, non-spec. insts should block other
|
||||
// non-spec insts because they can potentially be reading
|
||||
// system state that will be changed by the 1st non-spec inst.
|
||||
if (inst->isNonSpeculative()) {
|
||||
*nonSpecInstActive[tid] = false;
|
||||
DPRINTF(InOrderGraduation,
|
||||
"[tid:%i] Non-speculative inst [sn:%i] graduated\n",
|
||||
tid, inst->seqNum);
|
||||
lastNonSpecTick[tid] = cur_tick;
|
||||
}
|
||||
|
||||
if (inst->traceData) {
|
||||
inst->traceData->setStageCycle(stage_num, cur_tick);
|
||||
}
|
||||
|
||||
// Tell CPU that instruction is finished processing
|
||||
cpu->instDone(inst, tid);
|
||||
|
||||
grad_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
|
||||
}
|
||||
67
simulators/gem5/src/cpu/inorder/resources/graduation_unit.hh
Normal file
67
simulators/gem5/src/cpu/inorder/resources/graduation_unit.hh
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_GRAD_UNIT_HH__
|
||||
#define __CPU_INORDER_GRAD_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class GraduationUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
enum Command {
|
||||
CheckFault,
|
||||
GraduateInst
|
||||
};
|
||||
|
||||
public:
|
||||
GraduationUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu,
|
||||
ThePipeline::Params *params);
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
protected:
|
||||
Tick lastNonSpecTick[ThePipeline::MaxThreads];
|
||||
Tick lastFaultTick[ThePipeline::MaxThreads];
|
||||
bool *nonSpecInstActive[ThePipeline::MaxThreads];
|
||||
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_GRAD_UNIT_HH__
|
||||
241
simulators/gem5/src/cpu/inorder/resources/inst_buffer.cc
Normal file
241
simulators/gem5/src/cpu/inorder/resources/inst_buffer.cc
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/inst_buffer.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "debug/InOrderInstBuffer.hh"
|
||||
#include "debug/Resource.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.")
|
||||
.prereq(instsBypassed);
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
InstBuffer::execute(int slot_idx)
|
||||
{
|
||||
ResReqPtr ib_req = reqs[slot_idx];
|
||||
DynInstPtr inst = ib_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = ib_req->getStageNum();
|
||||
|
||||
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 = 20;
|
||||
RSkedPtr insert_sked = (stage_num >= ThePipeline::BackEndStartStage) ?
|
||||
inst->backSked : inst->frontSked;
|
||||
|
||||
insert_sked->push(new ScheduleEntry(next_stage,
|
||||
stage_pri,
|
||||
id,
|
||||
InstBuffer::InsertInst));
|
||||
|
||||
// Add to schedule: Remove from buffer in next next (bypass)
|
||||
// stage
|
||||
stage_pri = 20;
|
||||
RSkedPtr bypass_sked = (stage_num >= ThePipeline::BackEndStartStage) ?
|
||||
inst->backSked : inst->frontSked;
|
||||
|
||||
bypass_sked->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, inst->seqNum);
|
||||
insert(inst);
|
||||
inserted = true;
|
||||
} else {
|
||||
DPRINTF(InOrderInstBuffer, "[tid:%i]: Denying [sn:%i] request "
|
||||
"because buffer is full.\n", tid, inst->seqNum);
|
||||
|
||||
|
||||
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, inst->seqNum);
|
||||
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(ThreadID tid)
|
||||
{
|
||||
instList.pop_front();
|
||||
}
|
||||
|
||||
ThePipeline::DynInstPtr
|
||||
InstBuffer::top(ThreadID tid)
|
||||
{
|
||||
return instList.front();
|
||||
}
|
||||
|
||||
void
|
||||
InstBuffer::squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID 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);
|
||||
}
|
||||
92
simulators/gem5/src/cpu/inorder/resources/inst_buffer.hh
Normal file
92
simulators/gem5/src/cpu/inorder/resources/inst_buffer.hh
Normal file
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
|
||||
#define __CPU_INORDER_INST_BUFF_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.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);
|
||||
|
||||
void regStats();
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
void insert(DynInstPtr inst);
|
||||
|
||||
void remove(DynInstPtr inst);
|
||||
|
||||
void pop(ThreadID tid);
|
||||
|
||||
DynInstPtr top(ThreadID tid);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID 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__
|
||||
66
simulators/gem5/src/cpu/inorder/resources/mem_dep_unit.hh
Normal file
66
simulators/gem5/src/cpu/inorder/resources/mem_dep_unit.hh
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_MEM_DEP_UNIT_HH__
|
||||
#define __CPU_INORDER_MEM_DEP_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class MemDepUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
MemDepUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu);
|
||||
virtual ~MemDepUnit() {}
|
||||
|
||||
virtual void execute(int slot_num);
|
||||
|
||||
protected:
|
||||
Tick lastCycleGrad;
|
||||
int numCycleGrad;
|
||||
|
||||
bool *nonSpecInstActive[ThePipeline::MaxThreads];
|
||||
|
||||
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
/** @todo: Add Resource Stats Here */
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_GRAD_UNIT_HH__
|
||||
353
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.cc
Normal file
353
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.cc
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/mult_div_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "cpu/op_class.hh"
|
||||
#include "debug/InOrderMDU.hh"
|
||||
#include "debug/Resource.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), lastOpType(No_OpClass)
|
||||
{ }
|
||||
|
||||
void
|
||||
MultDivUnit::regStats()
|
||||
{
|
||||
multiplies
|
||||
.name(name() + ".multiplies")
|
||||
.desc("Number of Multipy Operations Executed");
|
||||
|
||||
divides
|
||||
.name(name() + ".divides")
|
||||
.desc("Number of Divide Operations Executed");
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
MultDivUnit::init()
|
||||
{
|
||||
// Set Up Resource Events to Appropriate Resource BandWidth
|
||||
resourceEvent = new MDUEvent[width];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new ResourceRequest(this);
|
||||
}
|
||||
|
||||
initSlots();
|
||||
}
|
||||
|
||||
//@TODO: Should we push this behavior into base-class to generically
|
||||
// accomodate all multicyle resources?
|
||||
void
|
||||
MultDivUnit::requestAgain(DynInstPtr inst, bool &service_request)
|
||||
{
|
||||
ResReqPtr mult_div_req = findRequest(inst);
|
||||
assert(mult_div_req);
|
||||
|
||||
service_request = true;
|
||||
|
||||
// Check to see if this instruction is requesting the same command
|
||||
// or a different one
|
||||
if (mult_div_req->cmd != inst->curSkedEntry->cmd) {
|
||||
// If different, then update command in the request
|
||||
mult_div_req->cmd = inst->curSkedEntry->cmd;
|
||||
DPRINTF(InOrderMDU,
|
||||
"[tid:%i]: [sn:%i]: Updating the command for this "
|
||||
"instruction\n", inst->readTid(), inst->seqNum);
|
||||
} else {
|
||||
// If same command, just check to see if access was completed
|
||||
// but dont try to re-execute
|
||||
DPRINTF(InOrderMDU,
|
||||
"[tid:%i]: [sn:%i]: requesting this resource again\n",
|
||||
inst->readTid(), inst->seqNum);
|
||||
}
|
||||
}
|
||||
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->curSkedEntry->cmd == reqs[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 = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderMDU,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
mult_div_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF(InOrderMDU, "Executing [sn:%i] ...\n", slot_num);
|
||||
|
||||
switch (mult_div_req->cmd)
|
||||
{
|
||||
case StartMultDiv:
|
||||
{
|
||||
DPRINTF(InOrderMDU, "Start MDU called ...\n");
|
||||
|
||||
OpClass op_class = inst->opClass();
|
||||
if (op_class == IntMultOp) {
|
||||
scheduleEvent(slot_num, multLatency);
|
||||
} else if (op_class == 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;
|
||||
}
|
||||
|
||||
// Allow to pass through to next stage while
|
||||
// event processes
|
||||
mult_div_req->setProcessing();
|
||||
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->isProcessing()) {
|
||||
DPRINTF(InOrderMDU, "Mult/Div finished.\n");
|
||||
mult_div_req->done();
|
||||
} else {
|
||||
mult_div_req->setCompleted(false);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MultDivUnit::exeMulDiv(int slot_num)
|
||||
{
|
||||
ResourceRequest* mult_div_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
|
||||
inst->fault = inst->execute();
|
||||
|
||||
if (inst->opClass() == IntMultOp) {
|
||||
multiplies++;
|
||||
} else if (inst->opClass() == IntDivOp) {
|
||||
divides++;
|
||||
}
|
||||
|
||||
if (inst->fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: The result of execution is 0x%x.\n",
|
||||
inst->readTid(), inst->readIntResult(0));
|
||||
} else {
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: [sn:%i]: had a %s "
|
||||
"fault.\n", inst->readTid(), inst->seqNum, inst->fault->name());
|
||||
}
|
||||
|
||||
mult_div_req->setProcessing(false);
|
||||
cpu->wakeCPU();
|
||||
}
|
||||
|
||||
void
|
||||
MultDivUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
ResReqPtr req_ptr = reqs[i];
|
||||
DynInstPtr inst = req_ptr->getInst();
|
||||
|
||||
if (req_ptr->valid &&
|
||||
inst->readTid() == tid &&
|
||||
inst->seqNum > squash_seq_num) {
|
||||
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: Squashing [sn:%i].\n",
|
||||
req_ptr->getInst()->readTid(),
|
||||
req_ptr->getInst()->seqNum);
|
||||
|
||||
req_ptr->setSquashed();
|
||||
|
||||
int req_slot_num = req_ptr->getSlot();
|
||||
|
||||
if (req_ptr->isProcessing())
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: Squashed [sn:%i], but "
|
||||
"waiting for MDU operation to complete.\n",
|
||||
req_ptr->getInst()->readTid(),
|
||||
req_ptr->getInst()->seqNum);
|
||||
else
|
||||
freeSlot(req_slot_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MDUEvent::MDUEvent()
|
||||
: ResourceEvent()
|
||||
{ }
|
||||
|
||||
void
|
||||
MDUEvent::process()
|
||||
{
|
||||
MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
|
||||
|
||||
mdu_res->exeMulDiv(slotIdx);
|
||||
|
||||
ResourceRequest* mult_div_req = resource->reqs[slotIdx];
|
||||
|
||||
if (mult_div_req->isSquashed())
|
||||
mdu_res->freeSlot(slotIdx);
|
||||
}
|
||||
|
||||
|
||||
139
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.hh
Normal file
139
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.hh
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
#include "cpu/op_class.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);
|
||||
|
||||
public:
|
||||
/** Override default Resource getSlot(). Will only getSlot if
|
||||
* valid mult/div sequence is being maintained
|
||||
*/
|
||||
int getSlot(DynInstPtr inst);
|
||||
|
||||
void init();
|
||||
|
||||
/** Get Operand Size For A Division Operation */
|
||||
int getDivOpSize(DynInstPtr inst);
|
||||
|
||||
/** Override default Resource execute */
|
||||
void execute(int slot_num);
|
||||
|
||||
void exeMulDiv(int slot_num);
|
||||
|
||||
/** Register extra resource stats */
|
||||
void regStats();
|
||||
|
||||
void requestAgain(DynInstPtr inst, bool &try_request);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid);
|
||||
|
||||
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 Multiplies */
|
||||
Stats::Scalar multiplies;
|
||||
|
||||
/** Number of Divides */
|
||||
Stats::Scalar divides;
|
||||
|
||||
MDUEvent *mduEvent;
|
||||
};
|
||||
|
||||
class MDUEvent : public ResourceEvent
|
||||
{
|
||||
public:
|
||||
MDUEvent();
|
||||
~MDUEvent() { }
|
||||
|
||||
|
||||
void process();
|
||||
};
|
||||
|
||||
|
||||
#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__
|
||||
48
simulators/gem5/src/cpu/inorder/resources/resource_list.hh
Normal file
48
simulators/gem5/src/cpu/inorder/resources/resource_list.hh
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_INORDER_RESOURCE_LIST_HH
|
||||
#define CPU_INORDER_RESOURCE_LIST_HH
|
||||
|
||||
#include "cpu/inorder/resources/agen_unit.hh"
|
||||
#include "cpu/inorder/resources/branch_predictor.hh"
|
||||
#include "cpu/inorder/resources/cache_unit.hh"
|
||||
#include "cpu/inorder/resources/decode_unit.hh"
|
||||
#include "cpu/inorder/resources/execution_unit.hh"
|
||||
#include "cpu/inorder/resources/fetch_seq_unit.hh"
|
||||
#include "cpu/inorder/resources/fetch_unit.hh"
|
||||
#include "cpu/inorder/resources/graduation_unit.hh"
|
||||
#include "cpu/inorder/resources/inst_buffer.hh"
|
||||
#include "cpu/inorder/resources/mult_div_unit.hh"
|
||||
#include "cpu/inorder/resources/tlb_unit.hh"
|
||||
#include "cpu/inorder/resources/use_def.hh"
|
||||
|
||||
#endif
|
||||
258
simulators/gem5/src/cpu/inorder/resources/tlb_unit.cc
Normal file
258
simulators/gem5/src/cpu/inorder/resources/tlb_unit.cc
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/tlb_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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)
|
||||
: Resource(res_name, res_id, res_width, res_latency, _cpu)
|
||||
{
|
||||
// Hard-Code Selection For Now
|
||||
if (res_name == "I-TLB")
|
||||
_tlb = params->itb;
|
||||
else if (res_name == "D-TLB")
|
||||
_tlb = params->dtb;
|
||||
else
|
||||
fatal("Unrecognized TLB name passed by user");
|
||||
|
||||
for (int i=0; i < MaxThreads; i++) {
|
||||
tlbBlocked[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
TheISA::TLB*
|
||||
TLBUnit::tlb()
|
||||
{
|
||||
return _tlb;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TLBUnit::init()
|
||||
{
|
||||
resourceEvent = new TLBUnitEvent[width];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new TLBUnitRequest(this);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TLBUnitRequest *tlb_req = dynamic_cast<TLBUnitRequest*>(reqs[slot_num]);
|
||||
tlb_req->setRequest(inst, stage_num, id, slot_num, cmd);
|
||||
return ud_req;
|
||||
}
|
||||
|
||||
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*>(reqs[slot_idx]);
|
||||
assert(tlb_req != 0x0);
|
||||
|
||||
DynInstPtr inst = tlb_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
int stage_num = tlb_req->getStageNum();
|
||||
|
||||
tlb_req->fault = NoFault;
|
||||
|
||||
assert(cpu->thread[tid]->getTC() != 0x0);
|
||||
assert(cpu->pipelineStage[stage_num] != 0x0);
|
||||
|
||||
switch (tlb_req->cmd)
|
||||
{
|
||||
case FetchLookup:
|
||||
{
|
||||
tlb_req->fault =
|
||||
_tlb->translateAtomic(tlb_req->memReq,
|
||||
cpu->thread[tid]->getTC(), TheISA::TLB::Execute);
|
||||
|
||||
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);
|
||||
|
||||
DPRINTF(InOrderTLB, "slot:%i sn:%i schedule event.\n", slot_idx, seq_num);
|
||||
|
||||
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 DataReadLookup:
|
||||
case DataWriteLookup:
|
||||
{
|
||||
DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
|
||||
tid, seq_num, tlb_req->memReq->getVaddr());
|
||||
|
||||
|
||||
TheISA::TLB::Mode tlb_mode = (tlb_req->cmd == DataReadLookup) ?
|
||||
TheISA::TLB::Read : TheISA::TLB::Write;
|
||||
|
||||
tlb_req->fault =
|
||||
_tlb->translateAtomic(tlb_req->memReq,
|
||||
cpu->thread[tid]->getTC(), tlb_mode);
|
||||
|
||||
if (tlb_req->fault != NoFault) {
|
||||
DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
|
||||
"addr:%08p for [sn:%i] %s.\n", tid, tlb_req->fault->name(),
|
||||
tlb_req->memReq->getVaddr(), seq_num, inst->instName());
|
||||
|
||||
if (inst->isDataPrefetch()) {
|
||||
DPRINTF(InOrderTLB, "Ignoring %s fault for data prefetch\n",
|
||||
tlb_req->fault->name());
|
||||
|
||||
tlb_req->fault = NoFault;
|
||||
|
||||
tlb_req->done();
|
||||
} else {
|
||||
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, inst);
|
||||
}
|
||||
} 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->reqs[slotIdx]->inst;
|
||||
int stage_num = resource->reqs[slotIdx]->getStageNum();
|
||||
ThreadID 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(tlb_res->reqs[slotIdx], tid);
|
||||
}
|
||||
|
||||
void
|
||||
TLBUnit::squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
ResReqPtr req_ptr = reqs[i];
|
||||
|
||||
if (req_ptr->valid &&
|
||||
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);
|
||||
|
||||
req_ptr->setSquashed();
|
||||
|
||||
int req_slot_num = req_ptr->getSlot();
|
||||
|
||||
tlbBlocked[tid] = false;
|
||||
|
||||
int stall_stage = reqs[req_slot_num]->getStageNum();
|
||||
|
||||
cpu->pipelineStage[stall_stage]->
|
||||
unsetResStall(reqs[req_slot_num], tid);
|
||||
|
||||
if (resourceEvent[req_slot_num].scheduled())
|
||||
unscheduleEvent(req_slot_num);
|
||||
|
||||
freeSlot(req_slot_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
151
simulators/gem5/src/cpu/inorder/resources/tlb_unit.hh
Normal file
151
simulators/gem5/src/cpu/inorder/resources/tlb_unit.hh
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/inst_buffer.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
|
||||
class TLBUnit : public Resource
|
||||
{
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
enum TLBCommand {
|
||||
FetchLookup,
|
||||
DataReadLookup,
|
||||
DataWriteLookup
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid);
|
||||
|
||||
bool tlbBlocked[ThePipeline::MaxThreads];
|
||||
|
||||
TheISA::TLB* tlb();
|
||||
|
||||
protected:
|
||||
/** List of instructions this resource is currently
|
||||
* processing.
|
||||
*/
|
||||
std::list<DynInstPtr> instList;
|
||||
|
||||
TheISA::TLB *_tlb;
|
||||
};
|
||||
|
||||
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)
|
||||
: ResourceRequest(res), memReq(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
RequestPtr memReq;
|
||||
|
||||
void setRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num,
|
||||
unsigned _cmd)
|
||||
{
|
||||
Addr aligned_addr;
|
||||
int req_size;
|
||||
unsigned flags;
|
||||
|
||||
if (_cmd == TLBUnit::FetchLookup) {
|
||||
aligned_addr = inst->getMemAddr();
|
||||
req_size = sizeof(TheISA::MachInst);
|
||||
flags = 0;
|
||||
inst->fetchMemReq = new Request(inst->readTid(), aligned_addr,
|
||||
req_size, flags,
|
||||
res->cpu->instMasterId(),
|
||||
inst->instAddr(),
|
||||
res->cpu->readCpuId(),
|
||||
inst->readTid());
|
||||
memReq = inst->fetchMemReq;
|
||||
} else {
|
||||
aligned_addr = inst->getMemAddr();;
|
||||
req_size = 0; //inst->getMemAccSize();
|
||||
flags = 0; //inst->getMemFlags();
|
||||
|
||||
if (req_size == 0 && (inst->isDataPrefetch() || inst->isInstPrefetch())) {
|
||||
req_size = 8;
|
||||
}
|
||||
|
||||
inst->dataMemReq = new Request(inst->readTid(), aligned_addr,
|
||||
req_size, flags,
|
||||
res->cpu->dataMasterId(),
|
||||
inst->instAddr(),
|
||||
res->cpu->readCpuId(),
|
||||
inst->readTid());
|
||||
memReq = inst->dataMemReq;
|
||||
}
|
||||
|
||||
ResourceRequest::setRequest(inst, stage_num, res_idx, slot_num, _cmd);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //__CPU_INORDER_TLB_UNIT_HH__
|
||||
509
simulators/gem5/src/cpu/inorder/resources/use_def.cc
Normal file
509
simulators/gem5/src/cpu/inorder/resources/use_def.cc
Normal file
@ -0,0 +1,509 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/use_def.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "debug/InOrderUseDef.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)
|
||||
{
|
||||
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
|
||||
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
|
||||
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
|
||||
serializeOnNextInst[tid] = false;
|
||||
serializeAfterSeqNum[tid] = 0;
|
||||
regDepMap[tid] = &cpu->archRegDepMap[tid];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::regStats()
|
||||
{
|
||||
uniqueRegsPerSwitch
|
||||
.name(name() + ".uniqueRegsPerSwitch")
|
||||
.desc("Number of Unique Registers Needed Per Context Switch")
|
||||
.prereq(uniqueRegsPerSwitch);
|
||||
|
||||
intRegFileReads
|
||||
.name(name() + ".intRegFileReads")
|
||||
.desc("Number of Reads from Int. Register File");
|
||||
|
||||
intRegFileWrites
|
||||
.name(name() + ".intRegFileWrites")
|
||||
.desc("Number of Writes to Int. Register File");
|
||||
|
||||
intRegFileAccs
|
||||
.name(name() + ".intRegFileAccesses")
|
||||
.desc("Total Accesses (Read+Write) to the Int. Register File");
|
||||
intRegFileAccs = intRegFileReads + intRegFileWrites;
|
||||
|
||||
floatRegFileReads
|
||||
.name(name() + ".floatRegFileReads")
|
||||
.desc("Number of Reads from FP Register File");
|
||||
|
||||
floatRegFileWrites
|
||||
.name(name() + ".floatRegFileWrites")
|
||||
.desc("Number of Writes to FP Register File");
|
||||
|
||||
floatRegFileAccs
|
||||
.name(name() + ".floatRegFileAccesses")
|
||||
.desc("Total Accesses (Read+Write) to the FP Register File");
|
||||
floatRegFileAccs = floatRegFileReads + floatRegFileWrites;
|
||||
|
||||
//@todo: add miscreg reads/writes
|
||||
// add forwarding by type???
|
||||
|
||||
regForwards
|
||||
.name(name() + ".regForwards")
|
||||
.desc("Number of Registers Read Through Forwarding Logic");
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::init()
|
||||
{
|
||||
// Set Up Resource Events to Appropriate Resource BandWidth
|
||||
if (latency > 0) {
|
||||
resourceEvent = new ResourceEvent[width];
|
||||
} else {
|
||||
resourceEvent = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new UseDefRequest(this);
|
||||
}
|
||||
|
||||
initSlots();
|
||||
}
|
||||
|
||||
ResReqPtr
|
||||
UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
|
||||
int slot_num, unsigned cmd)
|
||||
{
|
||||
UseDefRequest *ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_num]);
|
||||
ud_req->setRequest(inst, stage_num, id, slot_num, cmd,
|
||||
inst->curSkedEntry->idx);
|
||||
return ud_req;
|
||||
}
|
||||
|
||||
|
||||
ResReqPtr
|
||||
UseDefUnit::findRequest(DynInstPtr inst)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
UseDefRequest* ud_req =
|
||||
dynamic_cast<UseDefRequest*>(reqs[i]);
|
||||
assert(ud_req);
|
||||
|
||||
if (ud_req->valid &&
|
||||
ud_req->getInst() == inst &&
|
||||
ud_req->cmd == inst->curSkedEntry->cmd &&
|
||||
ud_req->useDefIdx == inst->curSkedEntry->idx) {
|
||||
return ud_req;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::execute(int slot_idx)
|
||||
{
|
||||
UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_idx]);
|
||||
DynInstPtr inst = ud_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
int ud_idx = ud_req->useDefIdx;
|
||||
|
||||
if (serializeOnNextInst[tid] &&
|
||||
seq_num > serializeAfterSeqNum[tid]) {
|
||||
inst->setSerializeBefore();
|
||||
serializeOnNextInst[tid] = false;
|
||||
}
|
||||
|
||||
if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
|
||||
cpu->instList[tid].front() != inst) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] Serialize before instruction encountered."
|
||||
" Blocking until pipeline is clear.\n", tid, seq_num);
|
||||
ud_req->done(false);
|
||||
return;
|
||||
} else if (inst->isStoreConditional() || inst->isSerializeAfter()) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] Serialize after instruction encountered."
|
||||
" Blocking until pipeline is clear.\n", tid, seq_num);
|
||||
serializeOnNextInst[tid] = true;
|
||||
serializeAfterSeqNum[tid] = seq_num;
|
||||
}
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderUseDef,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
ud_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
ud_req->done(false);
|
||||
return;
|
||||
} else if (inst->isNonSpeculative()) {
|
||||
*nonSpecInstActive[tid] = true;
|
||||
*nonSpecSeqNum[tid] = seq_num;
|
||||
}
|
||||
|
||||
switch (ud_req->cmd)
|
||||
{
|
||||
case ReadSrcReg:
|
||||
{
|
||||
InOrderCPU::RegType reg_type;
|
||||
RegIndex reg_idx = inst->_srcRegIdx[ud_idx];
|
||||
RegIndex flat_idx = cpu->flattenRegIdx(reg_idx, reg_type, tid);
|
||||
inst->flattenSrcReg(ud_idx, flat_idx);
|
||||
|
||||
if (flat_idx == TheISA::ZeroReg && reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Ignoring Reading of ISA-ZeroReg "
|
||||
"(Int. Reg %i).\n", tid, inst->seqNum, flat_idx);
|
||||
ud_req->done();
|
||||
return;
|
||||
} else {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Attempting to read source "
|
||||
"register idx %i (reg #%i, flat#%i).\n",
|
||||
tid, seq_num, ud_idx, reg_idx, flat_idx);
|
||||
}
|
||||
|
||||
if (regDepMap[tid]->canRead(reg_type, flat_idx, inst)) {
|
||||
switch (reg_type)
|
||||
{
|
||||
case InOrderCPU::IntType:
|
||||
{
|
||||
uniqueIntRegMap[flat_idx] = true;
|
||||
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Int Reg %i"
|
||||
" (%i) from Register File:0x%x.\n",
|
||||
tid, seq_num,
|
||||
reg_idx, flat_idx,
|
||||
cpu->readIntReg(flat_idx,inst->readTid()));
|
||||
inst->setIntSrc(ud_idx,
|
||||
cpu->readIntReg(flat_idx,
|
||||
inst->readTid()));
|
||||
intRegFileReads++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::FloatType:
|
||||
{
|
||||
uniqueFloatRegMap[flat_idx] = true;
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Float Reg %i"
|
||||
" (%i) from Register File:%x (%08f).\n",
|
||||
tid, seq_num,
|
||||
reg_idx - FP_Base_DepTag, flat_idx,
|
||||
cpu->readFloatRegBits(flat_idx,
|
||||
inst->readTid()),
|
||||
cpu->readFloatReg(flat_idx,
|
||||
inst->readTid()));
|
||||
|
||||
inst->setFloatSrc(ud_idx,
|
||||
cpu->readFloatReg(flat_idx,
|
||||
inst->readTid()));
|
||||
inst->setFloatRegBitsSrc(ud_idx,
|
||||
cpu->readFloatRegBits(flat_idx,
|
||||
inst->readTid()));
|
||||
floatRegFileReads++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::MiscType:
|
||||
{
|
||||
uniqueMiscRegMap[flat_idx] = true;
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Misc Reg %i "
|
||||
" (%i) from Register File:0x%x.\n",
|
||||
tid, seq_num,
|
||||
reg_idx - Ctrl_Base_DepTag, flat_idx,
|
||||
cpu->readMiscReg(flat_idx,
|
||||
inst->readTid()));
|
||||
inst->setIntSrc(ud_idx,
|
||||
cpu->readMiscReg(flat_idx,
|
||||
inst->readTid()));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Invalid Register Type: %i", reg_type);
|
||||
}
|
||||
|
||||
ud_req->done();
|
||||
} else {
|
||||
// Look for forwarding opportunities
|
||||
DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_type,
|
||||
flat_idx,
|
||||
inst);
|
||||
|
||||
if (forward_inst) {
|
||||
int dest_reg_idx =
|
||||
forward_inst->getDestIdxNum(flat_idx);
|
||||
|
||||
switch (reg_type)
|
||||
{
|
||||
case InOrderCPU::IntType:
|
||||
{
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
|
||||
" reg %i (%i), value 0x%x from "
|
||||
"[sn:%i] to [sn:%i] source #%x.\n",
|
||||
tid, reg_idx, flat_idx,
|
||||
forward_inst->readIntResult(dest_reg_idx),
|
||||
forward_inst->seqNum,
|
||||
inst->seqNum, ud_idx);
|
||||
inst->setIntSrc(ud_idx,
|
||||
forward_inst->
|
||||
readIntResult(dest_reg_idx));
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::FloatType:
|
||||
{
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
|
||||
" reg %i (%i) value 0x%x from "
|
||||
"[sn:%i] to [sn:%i] source #%i.\n",
|
||||
tid, reg_idx - FP_Base_DepTag, flat_idx,
|
||||
forward_inst->readFloatResult(dest_reg_idx),
|
||||
forward_inst->seqNum, inst->seqNum, ud_idx);
|
||||
inst->setFloatSrc(ud_idx,
|
||||
forward_inst->
|
||||
readFloatResult(dest_reg_idx));
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::MiscType:
|
||||
{
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
|
||||
" reg %i (%i) value 0x%x from "
|
||||
"[sn:%i] to [sn:%i] source #%i.\n",
|
||||
tid, reg_idx - Ctrl_Base_DepTag, flat_idx,
|
||||
forward_inst->readIntResult(dest_reg_idx),
|
||||
forward_inst->seqNum,
|
||||
inst->seqNum, ud_idx);
|
||||
inst->setIntSrc(ud_idx,
|
||||
forward_inst->
|
||||
readIntResult(dest_reg_idx));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Invalid Register Type: %i", reg_type);
|
||||
}
|
||||
|
||||
regForwards++;
|
||||
ud_req->done();
|
||||
} 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);
|
||||
ud_req->done(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WriteDestReg:
|
||||
{
|
||||
InOrderCPU::RegType reg_type;
|
||||
RegIndex reg_idx = inst->_destRegIdx[ud_idx];
|
||||
RegIndex flat_idx = cpu->flattenRegIdx(reg_idx, reg_type, tid);
|
||||
|
||||
if (flat_idx == TheISA::ZeroReg && reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(IntRegs, "[tid:%i]: Ignoring Writing of ISA-ZeroReg "
|
||||
"(Int. Reg %i)\n", tid, flat_idx);
|
||||
ud_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (regDepMap[tid]->canWrite(reg_type, flat_idx, inst)) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Flattening register idx %i "
|
||||
"(%i) and Attempting to write to Register File.\n",
|
||||
tid, seq_num, reg_idx, flat_idx);
|
||||
|
||||
switch (reg_type)
|
||||
{
|
||||
case InOrderCPU::IntType:
|
||||
{
|
||||
uniqueIntRegMap[flat_idx] = true;
|
||||
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Int. Result "
|
||||
"0x%x to register idx %i (%i).\n",
|
||||
tid, seq_num, inst->readIntResult(ud_idx),
|
||||
reg_idx, flat_idx);
|
||||
|
||||
// Remove Dependencies
|
||||
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
|
||||
|
||||
cpu->setIntReg(flat_idx,
|
||||
inst->readIntResult(ud_idx),
|
||||
inst->readTid());
|
||||
intRegFileWrites++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::FloatType:
|
||||
{
|
||||
uniqueFloatRegMap[flat_idx] = true;
|
||||
|
||||
// Remove Reg. Dependecny Block on this Register
|
||||
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
|
||||
|
||||
if (inst->resultType(ud_idx) ==
|
||||
InOrderDynInst::FloatBits) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing FP-Bits "
|
||||
"Result %08f (bits:0x%x) to register "
|
||||
"idx %i (%i).\n",
|
||||
tid, seq_num,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readFloatBitsResult(ud_idx),
|
||||
reg_idx - FP_Base_DepTag, flat_idx);
|
||||
|
||||
// Check for FloatRegBits Here
|
||||
cpu->setFloatRegBits(flat_idx,
|
||||
inst->readFloatBitsResult(ud_idx),
|
||||
inst->readTid());
|
||||
} else if (inst->resultType(ud_idx) ==
|
||||
InOrderDynInst::Float) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Float "
|
||||
"Result %08f (bits:0x%x) to register "
|
||||
"idx %i (%i).\n",
|
||||
tid, seq_num, inst->readFloatResult(ud_idx),
|
||||
inst->readIntResult(ud_idx),
|
||||
reg_idx - FP_Base_DepTag, flat_idx);
|
||||
|
||||
cpu->setFloatReg(flat_idx,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readTid());
|
||||
} else if (inst->resultType(ud_idx) ==
|
||||
InOrderDynInst::Double) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Double "
|
||||
"Result %08f (bits:0x%x) to register "
|
||||
"idx %i (%i).\n",
|
||||
tid, seq_num,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readIntResult(ud_idx),
|
||||
reg_idx - FP_Base_DepTag, flat_idx);
|
||||
|
||||
cpu->setFloatReg(flat_idx,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readTid());
|
||||
} else {
|
||||
panic("Result Type Not Set For [sn:%i] %s.\n",
|
||||
inst->seqNum, inst->instName());
|
||||
}
|
||||
|
||||
floatRegFileWrites++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::MiscType:
|
||||
{
|
||||
uniqueMiscRegMap[flat_idx] = true;
|
||||
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Writing Misc. 0x%x "
|
||||
"to register idx %i.\n",
|
||||
tid, inst->readIntResult(ud_idx), reg_idx - Ctrl_Base_DepTag);
|
||||
|
||||
// Remove Dependencies
|
||||
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
|
||||
|
||||
cpu->setMiscReg(flat_idx,
|
||||
inst->readIntResult(ud_idx),
|
||||
inst->readTid());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Invalid Register Type: %i", reg_type);
|
||||
}
|
||||
|
||||
ud_req->done();
|
||||
} else {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Dest. register idx: %i is "
|
||||
"not ready to write.\n",
|
||||
tid, seq_num, reg_idx);
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write "
|
||||
"register (idx=%i)\n",
|
||||
tid, reg_idx);
|
||||
ud_req->done(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MarkDestRegs:
|
||||
{
|
||||
regDepMap[tid]->insert(inst);
|
||||
ud_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
|
||||
{
|
||||
uniqueRegsPerSwitch = uniqueIntRegMap.size() + uniqueFloatRegMap.size()
|
||||
+ uniqueMiscRegMap.size();
|
||||
uniqueIntRegMap.clear();
|
||||
uniqueFloatRegMap.clear();
|
||||
uniqueMiscRegMap.clear();
|
||||
}
|
||||
134
simulators/gem5/src/cpu/inorder/resources/use_def.hh
Normal file
134
simulators/gem5/src/cpu/inorder/resources/use_def.hh
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
|
||||
class UseDefUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef TheISA::RegIndex RegIndex;
|
||||
|
||||
enum Command {
|
||||
ReadSrcReg,
|
||||
WriteDestReg,
|
||||
MarkDestRegs
|
||||
};
|
||||
|
||||
public:
|
||||
UseDefUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
void init();
|
||||
|
||||
ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num,
|
||||
unsigned cmd);
|
||||
|
||||
ResReqPtr findRequest(DynInstPtr inst);
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
void regStats();
|
||||
|
||||
protected:
|
||||
RegDepMap *regDepMap[ThePipeline::MaxThreads];
|
||||
|
||||
bool *nonSpecInstActive[ThePipeline::MaxThreads];
|
||||
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
bool serializeOnNextInst[ThePipeline::MaxThreads];
|
||||
InstSeqNum serializeAfterSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
Stats::Average uniqueRegsPerSwitch;
|
||||
std::map<RegIndex, bool> uniqueIntRegMap;
|
||||
std::map<RegIndex, bool> uniqueFloatRegMap;
|
||||
std::map<RegIndex, bool> uniqueMiscRegMap;
|
||||
|
||||
public:
|
||||
class UseDefRequest : public ResourceRequest {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
UseDefRequest(UseDefUnit *res)
|
||||
: ResourceRequest(res)
|
||||
{ }
|
||||
|
||||
int useDefIdx;
|
||||
|
||||
void setRequest(DynInstPtr _inst, int stage_num, int res_idx,
|
||||
int slot_num, unsigned _cmd, int idx)
|
||||
{
|
||||
useDefIdx = idx;
|
||||
|
||||
ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num,
|
||||
_cmd);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
/** Int. Register File Reads */
|
||||
Stats::Scalar intRegFileReads;
|
||||
|
||||
/** Int. Register File Writes */
|
||||
Stats::Scalar intRegFileWrites;
|
||||
|
||||
/** Int. Register File Total Accesses (Read+Write) */
|
||||
Stats::Formula intRegFileAccs;
|
||||
|
||||
/** Float Register File Reads */
|
||||
Stats::Scalar floatRegFileReads;
|
||||
|
||||
/** Float Register File Writes */
|
||||
Stats::Scalar floatRegFileWrites;
|
||||
|
||||
/** Float Register File Total Accesses (Read+Write) */
|
||||
Stats::Formula floatRegFileAccs;
|
||||
|
||||
/** Source Register Forwarding */
|
||||
Stats::Scalar regForwards;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_USE_DEF_UNIT_HH__
|
||||
251
simulators/gem5/src/cpu/inorder/thread_context.cc
Normal file
251
simulators/gem5/src/cpu/inorder/thread_context.cc
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2007 MIPS Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*
|
||||
*/
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/thread_context.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/InOrderCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
using namespace TheISA;
|
||||
|
||||
FSTranslatingPortProxy&
|
||||
InOrderThreadContext::getVirtProxy()
|
||||
{
|
||||
return thread->getVirtProxy();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::dumpFuncProfile()
|
||||
{
|
||||
thread->dumpFuncProfile();
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
InOrderThreadContext::readLastActivate()
|
||||
{
|
||||
return thread->lastActivate;
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
InOrderThreadContext::readLastSuspend()
|
||||
{
|
||||
return thread->lastSuspend;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::profileClear()
|
||||
{
|
||||
thread->profileClear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::profileSample()
|
||||
{
|
||||
thread->profileSample();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
|
||||
{
|
||||
// some things should already be set up
|
||||
assert(getSystemPtr() == old_context->getSystemPtr());
|
||||
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::Halted);
|
||||
|
||||
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->threadId(), 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->threadId());
|
||||
}
|
||||
|
||||
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->threadId());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::regStats(const std::string &name)
|
||||
{
|
||||
if (FullSystem) {
|
||||
thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system);
|
||||
thread->kernelStats->regStats(name + ".kern");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::serialize(std::ostream &os)
|
||||
{
|
||||
panic("serialize unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
panic("unserialize unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::copyArchRegs(ThreadContext *src_tc)
|
||||
{
|
||||
TheISA::copyRegs(src_tc, this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::clearArchRegs()
|
||||
{
|
||||
cpu->isa[thread->threadId()].clear();
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
InOrderThreadContext::readIntReg(int reg_idx)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenIntIndex(reg_idx);
|
||||
return cpu->readIntReg(reg_idx, tid);
|
||||
}
|
||||
|
||||
FloatReg
|
||||
InOrderThreadContext::readFloatReg(int reg_idx)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
return cpu->readFloatReg(reg_idx, tid);
|
||||
}
|
||||
|
||||
FloatRegBits
|
||||
InOrderThreadContext::readFloatRegBits(int reg_idx)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
return cpu->readFloatRegBits(reg_idx, tid);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
InOrderThreadContext::readRegOtherThread(int reg_idx, ThreadID tid)
|
||||
{
|
||||
return cpu->readRegOtherThread(reg_idx, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setIntReg(int reg_idx, uint64_t val)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenIntIndex(reg_idx);
|
||||
cpu->setIntReg(reg_idx, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
cpu->setFloatReg(reg_idx, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
cpu->setFloatRegBits(reg_idx, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val,
|
||||
ThreadID tid)
|
||||
{
|
||||
cpu->setRegOtherThread(misc_reg, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId());
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
cpu->setMiscReg(misc_reg, val, thread->threadId());
|
||||
}
|
||||
297
simulators/gem5/src/cpu/inorder/thread_context.hh
Normal file
297
simulators/gem5/src/cpu/inorder/thread_context.hh
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/thread_state.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "arch/kernel_stats.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
class CheckerCPU;
|
||||
namespace Kernel {
|
||||
class Statistics;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
/** @TODO: PERF: Should we bind this to a pointer in constructor? */
|
||||
TheISA::TLB *getITBPtr() { return cpu->getITBPtr(); }
|
||||
|
||||
/** Returns a pointer to the DTB. */
|
||||
/** @TODO: PERF: Should we bind this to a pointer in constructor? */
|
||||
TheISA::TLB *getDTBPtr() { return cpu->getDTBPtr(); }
|
||||
|
||||
/** Currently InOrder model does not support CheckerCPU, this is
|
||||
* merely here for supporting compilation of gem5 with the Checker
|
||||
* as a runtime option
|
||||
*/
|
||||
CheckerCPU *getCheckerCpuPtr() { return NULL; }
|
||||
|
||||
TheISA::Decoder *
|
||||
getDecoderPtr()
|
||||
{
|
||||
return cpu->getDecoderPtr(thread->contextId());
|
||||
}
|
||||
|
||||
System *getSystemPtr() { return cpu->system; }
|
||||
|
||||
/** Returns a pointer to this CPU. */
|
||||
BaseCPU *getCpuPtr() { return cpu; }
|
||||
|
||||
/** Returns a pointer to this CPU. */
|
||||
std::string getCpuName() { return cpu->name(); }
|
||||
|
||||
/** Reads this CPU's ID. */
|
||||
int cpuId() { return cpu->cpuId(); }
|
||||
|
||||
int contextId() { return thread->contextId(); }
|
||||
|
||||
void setContextId(int id) { thread->setContextId(id); }
|
||||
|
||||
/** Returns this thread's ID number. */
|
||||
int threadId() { return thread->threadId(); }
|
||||
void setThreadId(int id) { return thread->setThreadId(id); }
|
||||
|
||||
uint64_t readMicroPC()
|
||||
{ return 0; }
|
||||
|
||||
void setMicroPC(uint64_t val) { };
|
||||
|
||||
uint64_t readNextMicroPC()
|
||||
{ return 0; }
|
||||
|
||||
void setNextMicroPC(uint64_t val) { };
|
||||
|
||||
/** Returns a pointer to this thread's kernel statistics. */
|
||||
TheISA::Kernel::Statistics *getKernelStats()
|
||||
{ return thread->kernelStats; }
|
||||
|
||||
PortProxy &getPhysProxy() { return thread->getPhysProxy(); }
|
||||
|
||||
FSTranslatingPortProxy &getVirtProxy();
|
||||
|
||||
void initMemProxies(ThreadContext *tc)
|
||||
{ thread->initMemProxies(tc); }
|
||||
|
||||
/** Dumps the function profiling information.
|
||||
* @todo: Implement.
|
||||
*/
|
||||
void dumpFuncProfile();
|
||||
|
||||
/** Reads the last tick that this thread was activated on. */
|
||||
Tick readLastActivate();
|
||||
/** Reads the last tick that this thread was suspended on. */
|
||||
Tick readLastSuspend();
|
||||
|
||||
/** Clears the function profiling information. */
|
||||
void profileClear();
|
||||
|
||||
/** Samples the function profiling information. */
|
||||
void profileSample();
|
||||
|
||||
/** Returns pointer to the quiesce event. */
|
||||
EndQuiesceEvent *getQuiesceEvent()
|
||||
{
|
||||
return this->thread->quiesceEvent;
|
||||
}
|
||||
|
||||
SETranslatingPortProxy &getMemProxy() { return thread->getMemProxy(); }
|
||||
|
||||
/** Returns a pointer to this thread's process. */
|
||||
Process *getProcessPtr() { return thread->getProcessPtr(); }
|
||||
|
||||
/** Returns this thread's status. */
|
||||
Status status() const { return thread->status(); }
|
||||
|
||||
/** Sets this thread's status. */
|
||||
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. */
|
||||
void activate(int delay = 1);
|
||||
|
||||
/** Set the status to Suspended. */
|
||||
void suspend(int delay = 0);
|
||||
|
||||
/** Set the status to Halted. */
|
||||
void halt(int delay = 0);
|
||||
|
||||
/** Takes over execution of a thread from another CPU. */
|
||||
void takeOverFrom(ThreadContext *old_context);
|
||||
|
||||
/** Registers statistics associated with this TC. */
|
||||
void regStats(const std::string &name);
|
||||
|
||||
/** Serializes state. */
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
/** Unserializes state. */
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
/** Returns this thread's ID number. */
|
||||
int getThreadNum() { return thread->threadId(); }
|
||||
|
||||
/** Copies the architectural registers from another TC into this TC. */
|
||||
void copyArchRegs(ThreadContext *src_tc);
|
||||
|
||||
/** Resets all architectural registers to 0. */
|
||||
void clearArchRegs();
|
||||
|
||||
/** Reads an integer register. */
|
||||
uint64_t readIntReg(int reg_idx);
|
||||
|
||||
FloatReg readFloatReg(int reg_idx);
|
||||
|
||||
FloatRegBits readFloatRegBits(int reg_idx);
|
||||
|
||||
uint64_t readRegOtherThread(int misc_reg, ThreadID tid);
|
||||
|
||||
/** Sets an integer register to a value. */
|
||||
void setIntReg(int reg_idx, uint64_t val);
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val);
|
||||
|
||||
void setFloatRegBits(int reg_idx, FloatRegBits val);
|
||||
|
||||
void setRegOtherThread(int misc_reg,
|
||||
const MiscReg &val,
|
||||
ThreadID tid);
|
||||
|
||||
/** Reads this thread's PC. */
|
||||
TheISA::PCState pcState()
|
||||
{ return cpu->pcState(thread->threadId()); }
|
||||
|
||||
/** Sets this thread's PC. */
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{ cpu->pcState(val, thread->threadId()); }
|
||||
|
||||
/** Needs to be implemented for future CheckerCPU support.
|
||||
* See O3CPU for examples on how to integrate Checker.
|
||||
*/
|
||||
void pcStateNoRecord(const TheISA::PCState &val)
|
||||
{}
|
||||
|
||||
Addr instAddr()
|
||||
{ return cpu->instAddr(thread->threadId()); }
|
||||
|
||||
Addr nextInstAddr()
|
||||
{ return cpu->nextInstAddr(thread->threadId()); }
|
||||
|
||||
MicroPC microPC()
|
||||
{ return cpu->microPC(thread->threadId()); }
|
||||
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscRegNoEffect(int misc_reg)
|
||||
{ return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); }
|
||||
|
||||
/** Reads a misc. register, including any side-effects the
|
||||
* read might have as defined by the architecture. */
|
||||
MiscReg readMiscReg(int misc_reg)
|
||||
{ return cpu->readMiscReg(misc_reg, thread->threadId()); }
|
||||
|
||||
/** Sets a misc. register. */
|
||||
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. */
|
||||
void setMiscReg(int misc_reg, const MiscReg &val);
|
||||
|
||||
int flattenIntIndex(int reg)
|
||||
{ return cpu->isa[thread->threadId()].flattenIntIndex(reg); }
|
||||
|
||||
int flattenFloatIndex(int reg)
|
||||
{ return cpu->isa[thread->threadId()].flattenFloatIndex(reg); }
|
||||
|
||||
void activateContext(int delay)
|
||||
{ cpu->activateContext(thread->threadId(), delay); }
|
||||
|
||||
void deallocateContext()
|
||||
{ cpu->deallocateContext(thread->threadId()); }
|
||||
|
||||
/** Returns the number of consecutive store conditional failures. */
|
||||
// @todo: Figure out where these store cond failures should go.
|
||||
unsigned readStCondFailures()
|
||||
{ return thread->storeCondFailures; }
|
||||
|
||||
/** Sets the number of consecutive store conditional failures. */
|
||||
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. */
|
||||
bool misspeculating() { return false; }
|
||||
|
||||
/** Executes a syscall in SE mode. */
|
||||
void syscall(int64_t callnum)
|
||||
{ return cpu->syscall(callnum, thread->threadId()); }
|
||||
|
||||
/** Reads the funcExeInst counter. */
|
||||
Counter readFuncExeInst() { return thread->funcExeInst; }
|
||||
|
||||
void changeRegFileContext(unsigned param,
|
||||
unsigned val)
|
||||
{ panic("Not supported!"); }
|
||||
};
|
||||
|
||||
#endif
|
||||
44
simulators/gem5/src/cpu/inorder/thread_state.cc
Normal file
44
simulators/gem5/src/cpu/inorder/thread_state.cc
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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/cpu.hh"
|
||||
#include "cpu/inorder/thread_state.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
|
||||
using namespace TheISA;
|
||||
|
||||
void
|
||||
InOrderThreadState::dumpFuncProfile()
|
||||
{
|
||||
std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
|
||||
profile->dump(tc, *os);
|
||||
}
|
||||
97
simulators/gem5/src/cpu/inorder/thread_state.hh
Normal file
97
simulators/gem5/src/cpu/inorder/thread_state.hh
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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/isa_traits.hh"
|
||||
#include "base/callback.hh"
|
||||
#include "base/output.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/thread_state.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
class Event;
|
||||
class FunctionalMemory;
|
||||
class FunctionProfile;
|
||||
class InOrderCPU;
|
||||
class Process;
|
||||
class ProfileNode;
|
||||
|
||||
/**
|
||||
* 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, ThreadID _thread_num,
|
||||
Process *_process)
|
||||
: ThreadState(reinterpret_cast<BaseCPU*>(_cpu), _thread_num,
|
||||
_process),
|
||||
cpu(_cpu), inSyscall(0), trapPending(0), lastGradIsBranch(false)
|
||||
{ }
|
||||
|
||||
/** Handles the syscall. */
|
||||
void syscall(int64_t callnum) { process->syscall(callnum, tc); }
|
||||
|
||||
void dumpFuncProfile();
|
||||
|
||||
/** Pointer to the ThreadContext of this thread. */
|
||||
ThreadContext *tc;
|
||||
|
||||
/** Returns a pointer to the TC of this thread. */
|
||||
ThreadContext *getTC() { return tc; }
|
||||
|
||||
/** Is last instruction graduated a branch? */
|
||||
bool lastGradIsBranch;
|
||||
TheISA::PCState lastBranchPC;
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_THREAD_STATE_HH__
|
||||
45
simulators/gem5/src/cpu/inst_seq.hh
Normal file
45
simulators/gem5/src/cpu/inst_seq.hh
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003-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: Steve Raasch
|
||||
* Nathan Binkert
|
||||
*/
|
||||
|
||||
#ifndef __STD_TYPES_HH__
|
||||
#define __STD_TYPES_HH__
|
||||
|
||||
#include "base/types.hh"
|
||||
|
||||
// inst sequence type, used to order instructions in the ready list,
|
||||
// if this rolls over the ready list order temporarily will get messed
|
||||
// up, but execution will continue and complete correctly
|
||||
typedef uint64_t InstSeqNum;
|
||||
|
||||
// inst tag type, used to tag an operation instance in the IQ
|
||||
typedef unsigned int InstTag;
|
||||
|
||||
#endif // __STD_TYPES_HH__
|
||||
70
simulators/gem5/src/cpu/inteltrace.cc
Normal file
70
simulators/gem5/src/cpu/inteltrace.cc
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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: Steve Reinhardt
|
||||
* Lisa Hsu
|
||||
* Nathan Binkert
|
||||
* Steve Raasch
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/inteltrace.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
namespace Trace {
|
||||
|
||||
void
|
||||
Trace::IntelTraceRecord::dump()
|
||||
{
|
||||
ostream &outs = Trace::output();
|
||||
ccprintf(outs, "%7d ) ", when);
|
||||
outs << "0x" << hex << pc.instAddr() << ":\t";
|
||||
if (staticInst->isLoad()) {
|
||||
ccprintf(outs, "<RD %#x>", addr);
|
||||
} else if (staticInst->isStore()) {
|
||||
ccprintf(outs, "<WR %#x>", addr);
|
||||
}
|
||||
outs << endl;
|
||||
}
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ExeTracer Simulation Object
|
||||
//
|
||||
Trace::IntelTrace *
|
||||
IntelTraceParams::create()
|
||||
{
|
||||
return new Trace::IntelTrace(this);
|
||||
}
|
||||
89
simulators/gem5/src/cpu/inteltrace.hh
Normal file
89
simulators/gem5/src/cpu/inteltrace.hh
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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: Steve Reinhardt
|
||||
* Nathan Binkert
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INTELTRACE_HH__
|
||||
#define __CPU_INTELTRACE_HH__
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "base/types.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "debug/ExecEnable.hh"
|
||||
#include "debug/ExecSpeculative.hh"
|
||||
#include "params/IntelTrace.hh"
|
||||
#include "sim/insttracer.hh"
|
||||
|
||||
class ThreadContext;
|
||||
|
||||
namespace Trace {
|
||||
|
||||
class IntelTraceRecord : public InstRecord
|
||||
{
|
||||
public:
|
||||
IntelTraceRecord(Tick _when, ThreadContext *_thread,
|
||||
const StaticInstPtr _staticInst, TheISA::PCState _pc,
|
||||
bool spec, const StaticInstPtr _macroStaticInst = NULL)
|
||||
: InstRecord(_when, _thread, _staticInst, _pc, spec,
|
||||
_macroStaticInst)
|
||||
{
|
||||
}
|
||||
|
||||
void dump();
|
||||
};
|
||||
|
||||
class IntelTrace : public InstTracer
|
||||
{
|
||||
public:
|
||||
|
||||
IntelTrace(const IntelTraceParams *p) : InstTracer(p)
|
||||
{}
|
||||
|
||||
IntelTraceRecord *
|
||||
getInstRecord(Tick when, ThreadContext *tc,
|
||||
const StaticInstPtr staticInst, TheISA::PCState pc,
|
||||
const StaticInstPtr macroStaticInst = NULL)
|
||||
{
|
||||
if (!Debug::ExecEnable)
|
||||
return NULL;
|
||||
|
||||
if (!Trace::enabled)
|
||||
return NULL;
|
||||
|
||||
if (!Debug::ExecSpeculative && tc->misspeculating())
|
||||
return NULL;
|
||||
|
||||
return new IntelTraceRecord(when, tc,
|
||||
staticInst, pc, tc->misspeculating(), macroStaticInst);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#endif // __CPU_INTELTRACE_HH__
|
||||
70
simulators/gem5/src/cpu/intr_control.cc
Normal file
70
simulators/gem5/src/cpu/intr_control.cc
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2002-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: Nathan Binkert
|
||||
* Ron Dreslinski
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/intr_control.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/IntrControl.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
IntrControl::IntrControl(const Params *p)
|
||||
: SimObject(p), sys(p->sys)
|
||||
{}
|
||||
|
||||
void
|
||||
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->postInterrupt(int_num, index);
|
||||
}
|
||||
|
||||
void
|
||||
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->clearInterrupt(int_num, index);
|
||||
}
|
||||
|
||||
IntrControl *
|
||||
IntrControlParams::create()
|
||||
{
|
||||
return new IntrControl(this);
|
||||
}
|
||||
73
simulators/gem5/src/cpu/intr_control.hh
Normal file
73
simulators/gem5/src/cpu/intr_control.hh
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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: Nathan Binkert
|
||||
* Ron Dreslinski
|
||||
*/
|
||||
|
||||
#ifndef __INTR_CONTROL_HH__
|
||||
#define __INTR_CONTROL_HH__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "params/IntrControl.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
class IntrControl : public SimObject
|
||||
{
|
||||
public:
|
||||
System *sys;
|
||||
typedef IntrControlParams Params;
|
||||
IntrControl(const Params *p);
|
||||
|
||||
void clear(int cpu_id, int int_num, int index);
|
||||
void post(int cpu_id, int int_num, int index);
|
||||
|
||||
void
|
||||
clear(int int_num, int index = 0)
|
||||
{
|
||||
clear(0, int_num, index);
|
||||
}
|
||||
|
||||
void
|
||||
post(int int_num, int index = 0)
|
||||
{
|
||||
post(0, int_num, index);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __INTR_CONTROL_HH__
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user