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:
friemel
2012-10-24 19:18:57 +00:00
parent f7ff71bd46
commit b41eec3f65
3222 changed files with 658579 additions and 1 deletions

View 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

View 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")

View 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'

View 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'

View 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")

View 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'

View 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")

View 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'

View 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'

View 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' ])

View 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);
}

View 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__

View 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 &section)
{
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.
}

View 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 &section);
/**
* 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__

File diff suppressed because it is too large Load Diff

View 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;
}

View 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' })

View 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 &section)
{
}
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!");
}

View 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 &section);
// 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__

View 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;
}
}

View 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 &section)
{ 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__

View 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;
}
}

View 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__

View 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__

View 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;
}

View 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);
};

View 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);
}

View 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__

View 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);
}

View 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__

View 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")

View 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'

View 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')

View 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)

View 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__

File diff suppressed because it is too large Load Diff

View 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 &reg_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__

View 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;
}

View 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__

View 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);
}

View 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();
}

File diff suppressed because it is too large Load Diff

View 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);
};

View 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__

View 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__

File diff suppressed because it is too large Load Diff

View 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

View 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;
}
};

View 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

View 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;
}
};

View 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

View 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;
}
};

View 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

View 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

View 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");
}
}
}
}

View 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

View 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);
}

View 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__

View 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();
}

View 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();
}

View 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__

View 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++;
}
}
}

View 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__

View 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);
}
}

View 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__

View 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");
}
}*/
}

View 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__

View 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);
}

View File

@ -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__

File diff suppressed because it is too large Load Diff

View 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__

View 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);
}
}

View 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__

View 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);
}
}

View 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__

View 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]);
}

View 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

View 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();
}

View 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__

View 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);
}
}

View 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__

View 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);
}

View 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__

View 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__

View 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);
}

View 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__

View 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

View 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);
}
}
}

View 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__

View 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();
}

View 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__

View 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 &section)
{
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());
}

View 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 &section);
/** 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

View 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);
}

View 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__

View 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__

View 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);
}

View 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__

View 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);
}

View 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